home *** CD-ROM | disk | FTP | other *** search
/ Stone Design / Stone Design.iso / Stone_Friends / Wave / WavesWorld / Source / IBPalettes / WW3DKit / WW3DWell.m < prev    next >
Encoding:
Text File  |  1995-05-16  |  107.8 KB  |  3,208 lines

  1. // copyright 1993 Michael B. Johnson; some portions copyright 1994, MIT
  2. // see COPYRIGHT for reuse legalities
  3. //
  4.  
  5. /* Copyright 1993 Michael B. Johnson
  6.  * Permission to use, copy, modify, and distribute this
  7.  * software and its documentation for any non-commercial 
  8.  * purpose and without fee is hereby granted, provided that the 
  9.  * above copyright notice appears in all copies.  Michael B. Johnson
  10.  * makes no representations about the suitability of this
  11.  * software for any purpose.  It is provided "as is" without
  12.  * express or implied warranty.
  13.  *
  14.  * Permission to use, copy, modify or distribute this software
  15.  * and its documentation for any commercial purpose must be
  16.  * confirmed in writing with Michael B. Johnson.  He can be
  17.  * contacted at:
  18.  *              20 Ames St. E15-023G    
  19.  *              Cambridge, MA 02141
  20.  *              (617) 547 0563
  21.  *              
  22.  */
  23. #import "WW3DWell.h"
  24.  
  25. #import "WWTCLKit.h"
  26.  
  27. #import "WW3DCamera.h"
  28. #import "WW3DShader.h"
  29. #import "WW3DShape.h"
  30. #import "WW3DShapeBrowser.h"
  31. #import "WWEveParser.h"
  32. #import "WWShaderArgPointMatrix.h"
  33. #import "WWShaderArgColorWell.h"
  34. #import "WWShaderArgTextField.h"
  35. #import "WWDADLightView.h"
  36.  
  37. #import "EveCommand.h"
  38. #import "WWSceneClock.h"
  39.  
  40. #import "aspectRatios.h"
  41.  
  42. #import "WWRenderWrangler.h"
  43.  
  44. #import <apps/InterfaceBuilder.h>
  45.  
  46.  
  47. @implementation WW3DWell
  48.  
  49. #define BEZEL_X 7
  50. #define BEZEL_Y 7
  51.  
  52. #define WELL_X (BEZEL_X + 2)
  53. #define WELL_Y (BEZEL_Y + 2)
  54.  
  55.  
  56. + initialize { return [WW3DWell setVersion:5], self; }
  57.  
  58.  
  59. /*
  60. ==========================================================================
  61. subext() -- Remove extension from fname only if it is there.
  62.  
  63. ==========================================================================
  64. */
  65. static char 
  66. *subext(fname, ext)
  67. register char *fname, *ext;
  68. {
  69.   int fl, el;
  70.  
  71.     for ( fl = strlen(fname), el = strlen(ext);
  72.         --el > -1 && --fl > -1 && fname[fl] == ext[el]; )
  73.         ;
  74.     if (el == -1) 
  75.     {  fname[fl] = '\0';
  76.     }
  77.     return(fname);
  78. }
  79.  
  80.  
  81. /*
  82. ==========================================================================
  83. basename() -- deletes any prefix ending in `/' and the suffix.
  84.  
  85. ==========================================================================
  86. */
  87. static char 
  88. *basename(str, sfx, dest)
  89. char *str, *sfx, *dest;
  90. {
  91. char temp[1024];
  92. char *p, *p1;
  93. char *subext();
  94.  
  95.     p = p1 = temp;
  96.     strcpy(p, str);
  97.     while (*p) 
  98.     {  if (*p++ == '/') 
  99.            {  p1 = p;
  100.        }
  101.     }
  102.     strcpy (dest, subext(p1, sfx));
  103.     return(dest);
  104. }
  105.  
  106.  
  107. - initFrame:(const NXRect *)r 
  108. {
  109.    int     width, height;
  110.    //NXRect  newR;
  111.    const char  *WDRAG_PBTYPE[] = { NXFilenamePboardType, NULL};
  112.  
  113.  
  114.    selectedColor = NXConvertRGBToColor(0.9, 0.9, 0.0);
  115.    unselectedColor = NXConvertRGBToColor(0.9, 0.9, 0.9);
  116.  
  117.    replyTextColor = NXConvertRGBToColor(0.9, 0.0, 0.0);
  118.    sendTextColor = NXConvertRGBToColor(0.0, 0.0, 0.9);
  119.  
  120.    edgeClicked = NO;
  121.  
  122.    aspectRatioType = WW_ASPECT_DONT_CARE;
  123.    width = r->size.width;
  124.    height = r->size.height;
  125.    aspectRatio = width/height;
  126.  
  127.    //newR.origin.x = r->origin.x;
  128.    //newR.origin.y = r->origin.y;
  129.    //newR.size.width = newR.size.height = width;
  130.    //[super initFrame:&newR];
  131.  
  132.    [super initFrame:r];
  133.    [self registerForDraggedTypes:WDRAG_PBTYPE count:1];
  134.  
  135.    if ([NXApp respondsTo:@selector(isTestingInterface)]) // we're in IB
  136.    {  [window setDepthLimit:NX_TwelveBitRGBDepth];
  137.    }
  138.  
  139.    bezelRect.origin.x = BEZEL_X;
  140.    bezelRect.origin.y = BEZEL_Y;
  141.    bezelRect.size.width = width - (2 * BEZEL_X);
  142.    bezelRect.size.height = height - (2 * BEZEL_Y);
  143.  
  144.    wellRect.origin.x = WELL_X;
  145.    wellRect.origin.y = WELL_Y;
  146.    wellRect.size.width = width - (2 * WELL_X);
  147.    wellRect.size.height = height - (2 * WELL_Y);
  148.  
  149.    // A WW3DWell has a notion of a current scene, which is going on inside of it.
  150.    // The scene can be being built, or being replayed, or even being edited.
  151.    // when the scene is being built or edited, the WW3DWell's sceneClock provides
  152.    // information of where in the scene we are.  When the scene is being played
  153.    // back, the WW3DWell's camera is responsible for providing information about
  154.    // where in the scene we are.  One important difference is that when we are
  155.    // looking at the scene and the sceneClock is providing the time, it is an
  156.    // exact value.  When the scene is being played back, we can be at a region
  157.    // of time, since the camera thinks of time as a series of frames, and a
  158.    // frame can last for some amount of time (hence things can get motion blurred).
  159.  
  160.    // In the default, we assume that things are being simulated at a rate of 60Hz,
  161.    // and then the default camera runs at about 15 fps, and that a given scene
  162.    // starts at 0 and is only 10 seconds long.  For the average motion test, this
  163.    // is fine, and if you need more, well, change it...
  164.    sceneClock = [[WWSceneClock alloc] init];
  165.  
  166.    camera = [[WW3DCamera alloc] initFrame:&wellRect];
  167.    [camera setAutosizing:(NX_WIDTHSIZABLE | NX_HEIGHTSIZABLE)];
  168.    [camera setDelegate:self];
  169.    [camera setSceneClock:sceneClock];
  170.  
  171.    // this tickles a bug in the 3.2 release for HP; don't do it
  172.    //imageView = camera;
  173.    imageView = nil;
  174.    reuseImageView = YES;
  175.    useRendribInstead = NO;
  176.    beepWhenDone = YES;
  177.  
  178.    projectionType = N3D_Perspective;
  179.    [camera setProjection:projectionType];
  180.  
  181.    // stuff for RIBParser
  182.    ribParser = [[WWEveParser alloc] init]; 
  183.    [ribParser setSceneClock:sceneClock];
  184.    [camera setRunTimeSystem:ribParser];
  185.  
  186.    // oh boy, is this a hack...
  187.    [ribParser setViewToUpdate:camera];
  188.    [ribParser setWell:self];
  189.  
  190.    // just so everything's in synch to start...
  191.    [ribParser setRootShape:[camera worldShape]];
  192.  
  193.    [self setAutoresizeSubviews:YES];
  194.    if (![self addSubview:camera])
  195.    {  return nil;
  196.    }
  197.  
  198.    wellControlPanel = nil;
  199.    statusBufSize = 2048;
  200.    statusBuf = (char *)NXZoneCalloc([self zone], statusBufSize, sizeof(char));
  201.  
  202.    // need to make sure ribParser is initialized before I do this!!!
  203.    [sceneClock setScene:ribParser];
  204.    [sceneClock setDelegate:self];
  205.    [sceneClock setSamplesPerSecond:60];  // do this after setting the scene!
  206.  
  207.    imageViewWindowList = [[List alloc] init];
  208.  
  209.    return self;
  210. }
  211.  
  212. - awake
  213. {
  214.   const char  *WDRAG_PBTYPE[] = { NXFilenamePboardType, NULL};
  215.  
  216.  
  217.   [super awake];
  218.  
  219.   [self registerForDraggedTypes:WDRAG_PBTYPE count:1];
  220.   [camera sizeTo:wellRect.size.width :wellRect.size.height];
  221.   [camera setDelegate:self];
  222.  
  223.   projectionType = N3D_Perspective;
  224.   [camera setProjection:projectionType];
  225.   replyTextColor = NXConvertRGBToColor(0.9, 0.0, 0.0);
  226.   sendTextColor = NXConvertRGBToColor(0.0, 0.0, 0.9);
  227.   edgeClicked = NO;
  228.  
  229.   // stuff for RIBParser
  230.   ribParser = [[WWEveParser alloc] init]; 
  231.   [ribParser setSceneClock:sceneClock];
  232.   [camera setRunTimeSystem:ribParser];
  233.  
  234.   // oh boy, is this a hack...
  235.   [ribParser setViewToUpdate:camera];
  236.   [ribParser setWell:self];
  237.  
  238.   // just so everything's in synch to start...
  239.   [ribParser setRootShape:[camera worldShape]];
  240.  
  241.   // these should be archived, really...
  242.   selectedColor = NXConvertRGBToColor(0.9, 0.9, 0.0);
  243.   unselectedColor = NXConvertRGBToColor(0.9, 0.9, 0.9);
  244.  
  245.   wellControlPanel = nil;
  246.  
  247.   statusBufSize = 2048;
  248.   statusBuf = (char *)NXZoneCalloc([self zone], statusBufSize, sizeof(char));
  249.  
  250.    // need to make sure ribParser is initialized before I do this!!!
  251.    [sceneClock setScene:ribParser];
  252.    [sceneClock setDelegate:self];
  253.    [sceneClock setSamplesPerSecond:60];  // do this after setting the scene!
  254.  
  255.    imageViewWindowList = [[List alloc] init];
  256.  
  257.    // nil the (potentially) archived
  258.    if (imageView == camera)
  259.    { NXLogError("warning: setting imageView to nil to avoid tickling NeXT's 3.2 bug...\n"); 
  260.      imageView = nil;
  261.    }
  262.  
  263.    // in case we have an old camera; we need to reset our sceneClock as the sceneClock
  264.    [camera setSceneClock:sceneClock];
  265.  
  266.    return self;
  267. }
  268.  
  269. - free
  270. {
  271.   char  tmpFilename[64];
  272.   int   i, howMany = [imageViewWindowList count];
  273.   id    aWindow;
  274.  
  275.  
  276.   [statusText setStringValue:"freeing WW3DWell..."]; [statusText display]; NXPing();
  277.   [self unregisterDraggedTypes];
  278.  
  279.   for (i = 0; i < howMany; i++)
  280.   {  aWindow = [imageViewWindowList objectAt:i];
  281.      [aWindow setFreeWhenClosed:NO];
  282.      [aWindow close];
  283.      [aWindow free];  // that should automatically free the movie view
  284.   }
  285.   [imageViewWindowList free];
  286.   
  287.   // we want to free parser, because we want the ribParser, which
  288.   // might have traces set up in the rootShape of the camera to be able to
  289.   // untrace themselves cleanly...
  290.   [ribParser free];
  291.   // need to make sure the camera doesn't try to free its worldShape, since
  292.   // the ribParser just free'ed it
  293.   [camera setWorldShape:nil];
  294.   [camera setNoCurrentShape:nil];
  295.   [camera removeFromSuperview];
  296.   [camera free]; 
  297.  
  298.   // in order for the following to do the right thing, the
  299.   // wellControlPanel has to *not* free itself when closed.
  300.   // to make sure of this, we'll send it a don't free on 
  301.   // close message right before we close it...
  302.   [statusText setStringValue:"bye!"]; [statusText display]; NXPing();
  303.   if (statusBuf) { NXZoneFree([self zone], statusBuf); }
  304.  
  305.   [sceneClockControlPanel setFreeWhenClosed:NO];
  306.   [sceneClockControlPanel close];
  307.   [sceneClockControlPanel free];
  308.  
  309.   [wellControlPanel setFreeWhenClosed:NO];
  310.   [wellControlPanel close];
  311.  
  312.   // note that by free'ing the wellControlPanel, it should automatically
  313.   // free any panels it might have open, like the shape panel...
  314.   [wellControlPanel free];
  315.  
  316.   // blow away any tmp files I made...
  317.   sprintf(tmpFilename, "/tmp/foo%d.rib", getpid());
  318.   unlink(tmpFilename);
  319.   sprintf(tmpFilename, "/tmp/foo%d.tiff", getpid());
  320.   unlink(tmpFilename);
  321.   
  322.   return [super free];
  323. }
  324.  
  325. - reinitializeStuffFromZone:(NXZone *)zone
  326. {
  327.   return self;
  328. }
  329.  
  330. - copyFromZone:(NXZone *)zone
  331. {
  332.   id newCopy = [super copyFromZone:zone];
  333.  
  334.   [newCopy reinitializeStuffFromZone:zone];
  335.  
  336.   return newCopy;
  337. }
  338.  
  339. #define EPSILON 10
  340.  
  341. - sizeTo:(NXCoord)width :(NXCoord)height
  342. {
  343.   sprintf(statusBuf, "resizing to (%f, %f)...", width, height);
  344.   [statusText setStringValue:statusBuf]; [statusText display]; NXPing();
  345.   // don't want to make it too small...
  346.   if (width < ((2 * BEZEL_X) + EPSILON)) return nil;
  347.   if (height < ((2 * BEZEL_Y) + EPSILON)) return nil;
  348.  
  349.  
  350.   // let's say it comes in at 100, 100 and you're supposed to be constrained to 4:3
  351.   // you don't want it to get bigger than 100, 100, so... you frob the width, not the height
  352.   switch (aspectRatioType)
  353.   {  case WW_ASPECT_DONT_CARE:
  354.             aspectRatio = width/height;
  355.             [self revertControlPanel];
  356.             break;
  357.      case WW_ASPECT_NTSC:  // 1.33:1
  358.             height = width/1.33;
  359.             aspectRatio = 1.33;
  360.             break;
  361.      case WW_ASPECT_AMERICAN_WIDESCREEN:  // 1.85:1
  362.             //width = height * 1.85;
  363.             height = width/1.85;
  364.             aspectRatio = 1.85;
  365.             break;
  366.      case WW_ASPECT_EUROPEAN_WIDESCREEN:  // 1.66:1
  367.             //width = height * 1.66;
  368.             height = width/1.66;
  369.             aspectRatio = 1.66;
  370.             break;
  371.      case WW_ASPECT_VISTA_VISION:  // 2.21:1
  372.             //width = height * 1.21;
  373.             height = width/2.21;
  374.             aspectRatio = 2.21;
  375.             break;
  376.      case WW_ASPECT_SQUARE:  // 1:1
  377.             if (width < height)
  378.         {  height = width;
  379.         }
  380.         else
  381.         {  width = height;
  382.         }
  383.             aspectRatio = 1.0;
  384.             break;
  385.      case WW_ASPECT_CUSTOM:  //aspectX:aspectY
  386.             if (aspectRatio < 1.0)
  387.         {  width = height * aspectRatio;
  388.         }
  389.         else
  390.         {  height = width/aspectRatio;
  391.         }
  392.             break;
  393.      default:
  394.             NXLogError("unknown aspect ratio type: %d", aspectRatioType);
  395.             break;
  396.   }
  397.  
  398.   bezelRect.size.width = width - (2 * BEZEL_X);
  399.   bezelRect.size.height = height - (2 * BEZEL_Y);
  400.  
  401.   wellRect.size.width = width - (2 * WELL_X);
  402.   wellRect.size.height = height - (2 * WELL_Y);
  403.  
  404.   [super sizeTo:width :height];
  405.  
  406.   [camera sizeTo:wellRect.size.width :wellRect.size.height];
  407.   [window display];
  408.   sprintf(statusBuf, "resized to (%f, %f)", (width - 18), (height - 18));
  409.   [statusText setStringValue:statusBuf]; [statusText display]; NXPing();
  410.  
  411.   return self;
  412. }
  413.  
  414. // window delegate method to resize to right aspect ratio this should
  415. // be used when the rib well is the only view inside a window - Make the
  416. // rib well the delegate of the window and "you're all set..."
  417. - windowWillResize:sender toSize:(NXSize *)frameSize
  418. {
  419.   switch (aspectRatioType)
  420.   {  case WW_ASPECT_DONT_CARE:
  421.             break;
  422.      case WW_ASPECT_NTSC:  // 1.33:1
  423.             frameSize->height = frameSize->width/1.33;
  424.             break;
  425.      case WW_ASPECT_AMERICAN_WIDESCREEN:  // 1.85:1
  426.             frameSize->height = frameSize->width/1.85;
  427.             break;
  428.      case WW_ASPECT_EUROPEAN_WIDESCREEN:  // 1.66:1
  429.             frameSize->height = frameSize->width/1.66;
  430.             break;
  431.      case WW_ASPECT_VISTA_VISION:  // 2.21:1
  432.             frameSize->height = frameSize->width/2.21;
  433.             break;
  434.      case WW_ASPECT_SQUARE:  // 1:1
  435.             if (frameSize->width < frameSize->height)
  436.         {  frameSize->height = frameSize->width;
  437.         }
  438.         else
  439.         {  frameSize->width = frameSize->height;
  440.         }
  441.             break;
  442.      case WW_ASPECT_CUSTOM:  //aspectX:aspectY
  443.             if (aspectRatio < 1.0)
  444.         {  frameSize->width = frameSize->height * aspectRatio;
  445.         }
  446.         else
  447.         {  frameSize->height = frameSize->width/aspectRatio;
  448.         }
  449.             break;
  450.      default:
  451.             NXLogError("unknown aspect ratio type: %d - unable to change window size...", aspectRatioType);
  452.             break;
  453.   }
  454.   sprintf(statusBuf, "constrained window resizing to (%f, %f)...", frameSize->width, frameSize->height);
  455.   [statusText setStringValue:statusBuf]; [statusText display]; NXPing();
  456.  
  457.   return self;
  458. }
  459.  
  460.  
  461. - empty:sender
  462. {
  463.   // tell the camera it's worldShape is nil
  464.   [camera setWorldShape:nil];
  465.  
  466.   // tell the parser it's rootShape is nil
  467.   // it's smart enough to free the old one
  468.   [ribParser setRootShape:nil];
  469.   return self;
  470. }
  471.  
  472. - revertShapeInspectorFor:newShape
  473. {
  474.    RtMatrix  anRtMatrix;
  475.    RtBound   boundingBox;
  476.  
  477.  
  478.    // shape stuff
  479.    [self revertSurfaceShaderInspectorFor:[newShape shaderType:SLO_TYPE_SURFACE]];
  480.    [self revertDisplacementShaderInspectorFor:[newShape shaderType:SLO_TYPE_DISPLACEMENT]];
  481.  
  482.    [(WW3DShape *)newShape getBoundingBox:&boundingBox];
  483.    [[boundingBoxMatrix cellAt:0 :0] setFloatValue:boundingBox[0]];
  484.    [[boundingBoxMatrix cellAt:1 :0] setFloatValue:boundingBox[1]];
  485.    [[boundingBoxMatrix cellAt:0 :1] setFloatValue:boundingBox[2]];
  486.    [[boundingBoxMatrix cellAt:1 :1] setFloatValue:boundingBox[3]];
  487.    [[boundingBoxMatrix cellAt:0 :2] setFloatValue:boundingBox[4]];
  488.    [[boundingBoxMatrix cellAt:1 :2] setFloatValue:boundingBox[5]];
  489.    [newShape getTransformMatrix:anRtMatrix];
  490.    [self drawRtMatrix:anRtMatrix inMatrix:transformMatrix];
  491.  
  492.    [self fillRIBCommandsMatrix:ribCommandsMatrix];
  493.  
  494.    [boundingBoxMatrix display];
  495.    [transformMatrix display];
  496.    [ribCommandsMatrix display];
  497.   
  498.    return self;
  499. }
  500.  
  501. - enableCameraInspector
  502. {
  503.    if (cameraInspectorInvalid)
  504.    {  [eyePointMatrix setEnabled:YES];
  505.       [viewPointMatrix setEnabled:YES];
  506.       [rollAngleText setEnabled:YES];
  507.       [cameraTransformMatrix setEnabled:YES];
  508.  
  509.       [focalLengthText  setEnabled:YES];
  510.       [focalDistanceText  setEnabled:YES];
  511.       [fStopText  setEnabled:YES];
  512.       [exposureLengthText  setEnabled:YES];
  513.   
  514.       cameraInspectorInvalid = NO;
  515.    }
  516.   
  517.    return self;
  518. }
  519.  
  520. - invalidateCameraInspector
  521. {
  522.    if (!cameraInspectorInvalid)
  523.    {  [eyePointMatrix setEnabled:NO];
  524.       [viewPointMatrix setEnabled:NO];
  525.       [rollAngleText setEnabled:NO];
  526.       [cameraTransformMatrix setEnabled:NO];
  527.  
  528.       [focalLengthText  setEnabled:NO];
  529.       [focalDistanceText  setEnabled:NO];
  530.       [fStopText  setEnabled:NO];
  531.       [exposureLengthText  setEnabled:NO];
  532.   
  533.       // force redisplay
  534.       [eyePointMatrix display];
  535.       [viewPointMatrix display];
  536.       [cameraTransformMatrix display];
  537.  
  538.       cameraInspectorInvalid = YES;
  539.    }
  540.   
  541.    return self;
  542. }
  543.  
  544. - revertCameraInspector
  545. {
  546.    RtMatrix  anRtMatrix;
  547.    RtPoint   anEyePoint, aViewPoint;
  548.    RtFloat   aRollAngle;
  549.    float     elf;
  550.  
  551.    [self enableCameraInspector];
  552.  
  553.    [camera getEyeAt:&anEyePoint toward:&aViewPoint roll:&aRollAngle];
  554.    [[eyePointMatrix cellAt:0 :0] setFloatValue:anEyePoint[0]];
  555.    [[eyePointMatrix cellAt:0 :1] setFloatValue:anEyePoint[1]];
  556.    [[eyePointMatrix cellAt:0 :2] setFloatValue:anEyePoint[2]];
  557.    [[viewPointMatrix cellAt:0 :0] setFloatValue:aViewPoint[0]];
  558.    [[viewPointMatrix cellAt:0 :1] setFloatValue:aViewPoint[1]];
  559.    [[viewPointMatrix cellAt:0 :2] setFloatValue:aViewPoint[2]];
  560.    [rollAngleText setFloatValue:aRollAngle];
  561.  
  562.  
  563.    [camera getTransformMatrix:anRtMatrix];
  564.    [self drawRtMatrix:anRtMatrix inMatrix:cameraTransformMatrix];
  565.  
  566.    [focalLengthText setFloatValue:[camera focalLength]];
  567.    [focalDistanceText setFloatValue:[camera focalDistance]];
  568.    [fStopText setFloatValue:[camera fStop]];
  569.    [exposureLengthText setFloatValue:[camera exposureLength]];
  570.   
  571.    // WAVE: need to deal with shotOutputTypeMatrix here...
  572.  
  573.    [totalFrameCountText setIntValue:([camera endFrame] - [camera startFrame])];
  574.    [framesPerSecondText setFloatValue:[camera framesPerSecond]];
  575.    [shotLengthText setFloatValue:[camera shotLength]];
  576.    [frameNumberText setFloatValue:[camera frameNumber]];
  577.  
  578.    [shotStartTimeText setFloatValue:[camera shotStartTime]];
  579.    elf = [camera exposureLengthFactor];
  580.    [exposureLengthSlider setFloatValue:elf];
  581.    [exposureLengthPercentageText setFloatValue:(100. * elf)];
  582.    if (elf == 0.0)
  583.    {  [exposureLengthStrobeSwitch setIntValue:1];
  584.       [exposureLengthFilmSwitch setIntValue:0];
  585.       [exposureLengthVideoSwitch setIntValue:0];
  586.    }
  587.    else
  588.    {  if (elf == 0.5)
  589.       {  [exposureLengthStrobeSwitch setIntValue:0];
  590.          [exposureLengthFilmSwitch setIntValue:1];
  591.          [exposureLengthVideoSwitch setIntValue:0];
  592.       }
  593.       else
  594.       {  if (elf == 1.0)
  595.          {  [exposureLengthStrobeSwitch setIntValue:0];
  596.             [exposureLengthFilmSwitch setIntValue:0];
  597.             [exposureLengthVideoSwitch setIntValue:1];
  598.          }
  599.          else
  600.          {  [exposureLengthStrobeSwitch setIntValue:0];
  601.             [exposureLengthFilmSwitch setIntValue:0];
  602.             [exposureLengthVideoSwitch setIntValue:0];
  603.          }
  604.       }
  605.    }
  606.  
  607.    [binaryRIBSwitch setState:[camera binaryRIB]];
  608.    [reuseImageViewSwitch setState:reuseImageView];
  609.    [useRendribInsteadSwitch setState:[self useRendribInstead]];
  610.    [beepWhenDoneSwitch setState:beepWhenDone];
  611.  
  612.    // force redisplay
  613.    [eyePointMatrix display];
  614.    [viewPointMatrix display];
  615.    [cameraTransformMatrix display];
  616.   
  617.    cameraInspectorInvalid = YES;
  618.  
  619.    return self;
  620. }
  621.  
  622. - imageView { return imageView; }
  623.  
  624. - setCurrentShape:newShape
  625. {
  626.    [camera setCurrentShape:newShape];
  627.    [delegate wellWasUpdated:camera];
  628.    [[shapeBrowser loadColumnZero] selectRootShape];
  629.    return self;
  630. }
  631.  
  632. - setWorldShape:aShape
  633. {
  634.    [camera setWorldShape:aShape];
  635.    [camera setNoCurrentShape:nil];
  636.    [camera setCurrentShape:[camera worldShape]];  // set current shape to be top
  637.    [delegate wellWasUpdated:camera];
  638.    [[shapeBrowser loadColumnZero] selectRootShape];
  639.   return self;
  640. }
  641.  
  642.  
  643. - buildNewShapeHierarchyFromRIBFile:(const char *)filename 
  644. {
  645.    id aShape;
  646.  
  647.  
  648.    sprintf(statusBuf, "building new shape hierarchy from rib file %s...", filename);
  649.    [statusText setStringValue:statusBuf]; [statusText display]; NXPing();
  650.    if (filename && *filename)
  651.    {  // reset the sceneClock to the start of a new scene; really should probably make sure I can unwind this...
  652.       [sceneClock reset:nil];     
  653.       aShape = [ribParser buildNewShapeHierarchyFromRIBFile:filename];
  654.       if (!aShape) 
  655.       {  NXLogError("unable to build shape hierarchy from RIB file <%s>\n", filename);
  656.          return nil; 
  657.       }
  658.       [self setWorldShape:aShape];
  659.    }
  660.    [statusText setStringValue:"done"]; [statusText display]; NXPing();
  661.    [statusText setStringValue:"calculating bounding boxes..."]; [statusText display]; NXPing();
  662.    [[camera worldShape] calculateBoundingBoxStartingAt:[sceneClock timestamp] endingAt:[sceneClock timestamp]];
  663.    [statusText setStringValue:"done"]; [statusText display]; NXPing();
  664.    [camera display]; 
  665.    return self;
  666. }
  667.  
  668. - addToShapeHierarchyFromRIBFile:(const char *)filename 
  669. {
  670.    id aShape;
  671.  
  672.  
  673.   sprintf(statusBuf, "adding new shape hierarchy from rib file %s...", filename);
  674.   [statusText setStringValue:statusBuf]; [statusText display]; NXPing();
  675.    if (filename && *filename)
  676.    {  [ribParser setRootShapeInUse:YES];
  677.       aShape = [ribParser buildNewShapeHierarchyFromRIBFile:filename :NO];
  678.       if (!aShape) 
  679.       {  NXLogError("unable to build shape hierarchy from RIB file <%s>\n", filename);
  680.          [ribParser setRootShapeInUse:NO];
  681.          return nil; 
  682.       }
  683.       [[camera currentShape] addChild:aShape]; // don't free the old one cause it might be shared - need a way to track this... 
  684.       [self setCurrentShape:aShape];
  685.    }
  686.    [statusText setStringValue:"done"]; [statusText display]; NXPing();
  687.    [statusText setStringValue:"calculating bounding boxes..."]; [statusText display]; NXPing();
  688.    [[camera worldShape] calculateBoundingBoxStartingAt:[sceneClock timestamp] endingAt:[sceneClock timestamp]];
  689.    [statusText setStringValue:"done"]; [statusText display]; NXPing();
  690.    [camera display]; 
  691.    return self;
  692. }
  693.  
  694. - buildNewShapeHierarchyFromEveFile:(const char *)filename 
  695. {
  696.    id aShape;
  697.  
  698.  
  699.    sprintf(statusBuf, "building new shape hierarchy from eve file %s...", filename);
  700.    [statusText setStringValue:statusBuf]; [statusText display]; NXPing();
  701.    if (filename && *filename)
  702.    {  // reset the sceneClock to the start of a new scene; really should probably make sure I can unwind this...
  703.       [sceneClock reset:nil];     
  704.       [camera setWorldShape :nil];     
  705.       [camera setNoCurrentShape:nil];
  706.       aShape = [ribParser buildNewShapeHierarchyFromEveFile:filename];
  707.       if (!aShape) 
  708.       {  NXLogError("unable to build shape hierarchy from Eve file <%s>\n", filename);
  709.          return nil; 
  710.       }
  711.       [self setWorldShape:aShape];
  712.    }
  713.    [statusText setStringValue:"done"]; [statusText display]; NXPing();
  714.    [statusText setStringValue:"calculating bounding boxes..."]; [statusText display]; NXPing();
  715.    [[camera worldShape] calculateBoundingBoxStartingAt:[sceneClock timestamp] endingAt:[sceneClock timestamp]];
  716.    [statusText setStringValue:"done"]; [statusText display]; NXPing();
  717.    [camera display]; 
  718.    return self;
  719. }
  720.  
  721. - readMdlTemplateFile:(const char *)filename 
  722. {
  723.    static char  thePath[MAXPATHLEN+1];
  724.  
  725.  
  726.    sprintf(statusBuf, "reading model template file %s...", filename);
  727.    [statusText setStringValue:statusBuf]; [statusText display]; NXPing();
  728.    if (filename && *filename)
  729.    {  // set the modelPath tcl variable to be the path of the .mdl file, 
  730.       // and then tell the tcl interp to parse the file
  731.       [[ribParser tclInterp] setVar:"modelPath" toValue:(char *)filename];
  732.       sprintf(thePath, "%s/model.eve", filename);
  733.       [self evaluateEveFile:thePath];
  734.    }
  735.    [statusText setStringValue:"done"]; [statusText display]; NXPing();
  736.   return self;
  737. }
  738.  
  739. - buildNewShapeHierarchyFromMdlFile:(const char *)filename 
  740. {
  741.    char  thePath[MAXPATHLEN+1];
  742.  
  743.  
  744.    sprintf(statusBuf, "building new shape hierarchy from model file package %s...", filename);
  745.    [statusText setStringValue:statusBuf]; [statusText display]; NXPing();
  746.    if (filename && *filename)
  747.    {  // reset the sceneClock to the start of a new scene; really should probably make sure I can unwind this...
  748.       [sceneClock reset:nil];     
  749.       // set the modelPath tcl variable to be the path of the .mdl file, 
  750.       // and then tell the tcl interp to parse the file
  751.       [[ribParser tclInterp] setVar:"modelPath" toValue:(char *)filename];
  752.       sprintf(thePath, "%s/model.eve", filename);
  753.       [self buildNewShapeHierarchyFromEveFile:thePath];
  754.    }
  755.    [statusText setStringValue:"done"]; [statusText display]; NXPing();
  756.    [statusText setStringValue:"calculating bounding boxes..."]; [statusText display]; NXPing();
  757.    [[camera worldShape] calculateBoundingBoxStartingAt:[sceneClock timestamp] endingAt:[sceneClock timestamp]];
  758.    [statusText setStringValue:"done"]; [statusText display]; NXPing();
  759.    return self;
  760. }
  761.  
  762. - addToShapeHierarchyFromMdlFile:(const char *)filename 
  763. {
  764.    char  thePath[MAXPATHLEN+1];
  765.  
  766.  
  767.    sprintf(statusBuf, "adding new shape hierarchy from model file package %s...", filename);
  768.    [statusText setStringValue:statusBuf]; [statusText display]; NXPing();
  769.    if (filename && *filename)
  770.    {  // set the modelPath tcl variable to be the path of the .mdl file, 
  771.       // and then tell the tcl interp to parse the file
  772.       [[ribParser tclInterp] setVar:"modelPath" toValue:(char *)filename];
  773.       sprintf(thePath, "%s/model.eve", filename);
  774.       [self addToShapeHierarchyFromEveFile:thePath];
  775.    }
  776.    [statusText setStringValue:"done"]; [statusText display]; NXPing();
  777.    [statusText setStringValue:"calculating bounding boxes..."]; [statusText display]; NXPing();
  778.    [[camera worldShape] calculateBoundingBoxStartingAt:[sceneClock timestamp] endingAt:[sceneClock timestamp]];
  779.    [statusText setStringValue:"done"]; [statusText display]; NXPing();
  780.    return self;
  781. }
  782.  
  783.  
  784. - buildNewShapeHierarchyFromSceneFile:(const char *)filename 
  785. {
  786.    id aShape;
  787.  
  788.  
  789.    sprintf(statusBuf, "building new shape hierarchy from scene file %s...", filename);
  790.    [statusText setStringValue:statusBuf]; [statusText display]; NXPing();
  791.    if (filename && *filename)
  792.    {  // reset the sceneClock to the start of a new scene; really should probably make sure I can unwind this...
  793.       [sceneClock reset:nil];     
  794.       [camera setWorldShape :nil];     
  795.       [camera setNoCurrentShape:nil];
  796.       [ribParser setFrozen:YES];
  797.       aShape = [ribParser buildNewShapeHierarchyFromEveFile:filename];
  798.       [ribParser setFrozen:NO];
  799.       if (!aShape) 
  800.       {  NXLogError("unable to build shape hierarchy from Eve file <%s>\n", filename);
  801.          return nil; 
  802.       }
  803.       [self setWorldShape:aShape];
  804.    }
  805.    [statusText setStringValue:"done"]; [statusText display]; NXPing();
  806.    [statusText setStringValue:"calculating bounding boxes..."]; [statusText display]; NXPing();
  807.    [[camera worldShape] calculateBoundingBoxStartingAt:[sceneClock timestamp] endingAt:[sceneClock timestamp]];
  808.    [statusText setStringValue:"done"]; [statusText display]; NXPing();
  809.    [camera display]; 
  810.    return self;
  811. }
  812.  
  813. - addToShapeHierarchyFromSceneFile:(const char *)filename 
  814. {
  815.    id aShape;
  816.  
  817.  
  818.   sprintf(statusBuf, "adding new shape hierarchy from eve file %s...", filename);
  819.   [statusText setStringValue:statusBuf]; [statusText display]; NXPing();
  820.    if (filename && *filename)
  821.    { // tell the rib parser not to blow away it's old root shape
  822.      [ribParser setFrozen:YES];
  823.      [ribParser setRootShapeInUse:YES];
  824.      aShape = [ribParser buildNewShapeHierarchyFromEveFile:filename :NO];
  825.      [ribParser setFrozen:NO];
  826.      if (!aShape) 
  827.      {  NXLogError("unable to build shape hierarchy from EVE file <%s>\n", filename);
  828.         [ribParser setRootShapeInUse:NO];
  829.         return nil; 
  830.      }
  831.      [[camera currentShape] addChild:aShape]; // don't free the old one cause it might be shared - need a way to track this... 
  832.      [self setCurrentShape:aShape];
  833.    }
  834.    [statusText setStringValue:"done"]; [statusText display]; NXPing();
  835.    [statusText setStringValue:"calculating bounding boxes..."]; [statusText display]; NXPing();
  836.    [[camera worldShape] calculateBoundingBoxStartingAt:[sceneClock timestamp] endingAt:[sceneClock timestamp]];
  837.    [statusText setStringValue:"done"]; [statusText display]; NXPing();
  838.    [camera display]; 
  839.    return self;
  840. }
  841.  
  842.  
  843. - addToShapeHierarchyFromEveFile:(const char *)filename 
  844. {
  845.    id aShape;
  846.  
  847.  
  848.   sprintf(statusBuf, "adding new shape hierarchy from eve file %s...", filename);
  849.   [statusText setStringValue:statusBuf]; [statusText display]; NXPing();
  850.    if (filename && *filename)
  851.    { // tell the rib parser not to blow away it's old root shape
  852.      [ribParser setRootShapeInUse:YES];
  853.      aShape = [ribParser buildNewShapeHierarchyFromEveFile:filename :NO];
  854.      if (!aShape) 
  855.      {  NXLogError("unable to build shape hierarchy from EVE file <%s>\n", filename);
  856.         [ribParser setRootShapeInUse:NO];
  857.         return nil; 
  858.      }
  859.      [[camera currentShape] addChild:aShape]; // don't free the old one cause it might be shared - need a way to track this... 
  860.      [self setCurrentShape:aShape];
  861.    }
  862.    [statusText setStringValue:"done"]; [statusText display]; NXPing();
  863.    [statusText setStringValue:"calculating bounding boxes..."]; [statusText display]; NXPing();
  864.    [[camera worldShape] calculateBoundingBoxStartingAt:[sceneClock timestamp] endingAt:[sceneClock timestamp]];
  865.    [statusText setStringValue:"done"]; [statusText display]; NXPing();
  866.    [camera display]; 
  867.    return self;
  868. }
  869.  
  870. - evaluateEveFile:(const char *)filename 
  871. {
  872.    if (filename && *filename)
  873.    {  if ([ribParser evaluateEveFile:filename])
  874.       {  return self;
  875.       }
  876.    }
  877.    return nil;
  878. }
  879.  
  880.  
  881. - turnOffCropWindow { [camera turnOffCropWindow]; return self; }
  882.  
  883.  
  884. - shape { return [camera worldShape]; }
  885. - parser { return ribParser; }
  886. - camera { return camera; }
  887.  
  888. - drawSelf:(const NXRect *)r :(int)n 
  889. {
  890.   NXDrawButton(r, r);
  891.   if (edgeClicked)
  892.   {  PSsetgray(NX_WHITE);
  893.      PSrectfill((r->origin.x + 1), (r->origin.y + 1), (r->size.width - 2), (r->size.height - 2));
  894.   }
  895.   NXDrawGrayBezel(&bezelRect, &bezelRect);
  896.  
  897.   return self;
  898. }
  899.  
  900. - windowWillClose:sender
  901. {
  902.   int   i = 0, 
  903.         howMany = [imageViewWindowList count];
  904.   BOOL  done = NO;
  905.  
  906.  
  907.   if (wellControlPanel && (sender == wellControlPanel))
  908.   { edgeClicked = NO;
  909.     wellControlPanel = nil;
  910.     [self display];
  911.     return self;
  912.   }
  913.  
  914.  
  915.   // if it's one of the imageViewWindows, delete it from the list...
  916.   while (!done && (i < howMany)) 
  917.   {  if (sender == [imageViewWindowList objectAt:i])
  918.      {  [imageViewWindowList removeObjectAt:i];
  919.         done = YES;
  920.      }
  921.      i++;
  922.   }
  923.   // if it's the current imageViewWindow, nil out it and it's view
  924.   if (sender == imageViewWindow)
  925.   {  imageView = nil;
  926.      imageViewWindow = nil;
  927.   }
  928.   return self;
  929. }
  930.  
  931. - revertSceneClockInspector
  932. {
  933.   [sceneClockSamplesPerSecondText setFloatValue:[sceneClock samplesPerSecond]];
  934.   [sceneClockTimeText setFloatValue:[sceneClock timestamp]];
  935.   [sceneClockIncrementText setFloatValue:[sceneClock increment]];
  936.   [sceneClockSkipText setFloatValue:[sceneClock skip]];
  937.   [sceneClockRatioText setFloatValue:[sceneClock ratio]];
  938.  
  939.   if ([sceneClock isPaused])
  940.   {  [sceneClockButtonMatrix selectCellWithTag:2]; // really should #define this somewhere, doofus
  941.   }
  942.  
  943.   [sceneClockMarkText setFloatValue:[sceneClock mark]];
  944.  
  945.   // is this the best place to do this?
  946.   [self synchCameraToSceneClock];
  947.  
  948.   return self;
  949. }
  950.  
  951. - revertControlPanel
  952. {
  953.   if (!wellControlPanel)  // this should speed stuff up a lot when the panel's not around...
  954.   {  return self;
  955.   }
  956.   
  957.   [statusText setStringValue:"reverting control panel..."]; [statusText display]; NXPing();
  958.  
  959.   // note that I'm leaking here...
  960.   [shapeBrowser setPath:[[camera currentShape] getPath]];
  961.  
  962.   [ignoreShadingRateSwitch setState:[ribParser ignoreShadingRate]];
  963.   [ignoreColorsSwitch setState:[ribParser ignoreColors]];
  964.   [ignoreLightsSwitch setState:[ribParser ignoreLights]];
  965.   [ignoreShadersSwitch setState:[ribParser ignoreShaders]];
  966.   [firmTransformsSwitch setState:[ribParser firmTransforms]];
  967.   [treatAttributeBeginLikeStartShapeSwitch setState:[ribParser treatAttributeBeginLikeStartShape]];
  968.   [treatTransformBeginLikeAttributeBeginSwitch setState:[ribParser treatTransformBeginLikeAttributeBegin]];
  969.   [applyShadersDirectlyToCurrentShapeSwitch setState:[ribParser applyShadersDirectlyToCurrentShape]];
  970.   [lowRezTesselationText setFloatValue:[camera lowRezTesselation]];
  971.   [tesselationText setFloatValue:[camera tesselation]];
  972.   [projectionTypeMatrix selectCellWithTag:projectionType];
  973.   [selectedColorWell setColor:selectedColor];
  974.   [unselectedColorWell setColor:unselectedColor];
  975.   [shadingRateText setFloatValue:[camera shadingRate]];
  976.   [shadingRateSlider setFloatValue:[camera shadingRate]];
  977.   [binaryRIBSwitch setState:[camera binaryRIB]];
  978.   if ([self useRendribInstead])
  979.   {  [shadingRateText setEnabled:NO];
  980.      [shadingRateSlider setEnabled:NO];
  981.   }
  982.   else
  983.   {  [shadingRateText setEnabled:YES];
  984.      [shadingRateSlider setEnabled:YES];
  985.   }
  986.  
  987.   [aspectRatioMatrix selectCellWithTag:aspectRatioType];
  988.   [customAspectRatioText setFloatValue:aspectRatio];
  989.   [customAspectRatioText setEnabled:(aspectRatioType == WW_ASPECT_CUSTOM)];
  990.   [fovText setFloatValue:[camera fieldOfView]];
  991.   [fovSlider setFloatValue:[camera fieldOfView]];
  992.   [trackballAffectsMatrix selectCellWithTag:[camera trackballAffects]];
  993.   [trackballXYZMatrix selectCellWithTag:[camera trackballXYZ]];
  994.  
  995.    [renderWorldAsBoxSwitch setState:[camera renderWorldAsBox]];
  996.   [renderCurrentAsBoxSwitch setState:[camera renderCurrentAsBox]];
  997.   [worldIsVisibleSwitch setState:[camera worldIsVisible]];
  998.   [currentIsVisibleSwitch setState:[camera currentIsVisible]];
  999.  
  1000.   [backgroundColorWell setColor:[camera backgroundColor]];
  1001.  
  1002.   [showSelectedShapeSwitch setState:[camera showSelectedShape]];
  1003.   [drawOriginForSelectedShapeSwitch setState:[camera drawOriginForSelectedShape]];
  1004.   [renderStyleMatrix selectCellWithTag:[camera renderStyle]];
  1005.   [movingRenderStyleMatrix selectCellWithTag:[camera movingRenderStyle]];
  1006.  
  1007.   // shape stuff
  1008.   [self revertShapeInspectorFor:[camera currentShape]];
  1009.  
  1010.   // camera stuff
  1011.   [self revertCameraInspector];
  1012.  
  1013.   // scene stuff
  1014.   [self revertSceneClockInspector];
  1015.   [statusText setStringValue:"done"]; [statusText display]; NXPing();
  1016.   return self;
  1017. }
  1018.  
  1019. - takeShowSelectedShape:sender 
  1020. {  [camera setShowSelectedShape:[sender intValue]]; 
  1021.    [self revertControlPanel]; 
  1022.    [delegate sceneWasUpdated:camera]; 
  1023.    [self display];
  1024.    return self; 
  1025. }
  1026.  
  1027. - takeDrawOriginForSelectedShape:sender 
  1028. {  [camera setDrawOriginForSelectedShape:[sender intValue]]; 
  1029.    [self revertControlPanel]; 
  1030.    [delegate sceneWasUpdated:camera]; 
  1031.    [self display];
  1032.    return self; 
  1033. }
  1034.  
  1035. - takeRenderStyleFromMatrix:sender 
  1036. {  [camera setRenderStyle:[[sender selectedCell] tag]]; 
  1037.    [self revertControlPanel]; 
  1038.    return self; 
  1039. }
  1040.  
  1041. - takeMovingRenderStyleFromMatrix:sender 
  1042. {  [camera setMovingRenderStyle:[[sender selectedCell] tag]]; 
  1043.    [self revertControlPanel]; 
  1044.    return self; 
  1045. }
  1046.  
  1047. - loadImageView
  1048. {  id     bundle = [NXBundle bundleForClass: [self class]];
  1049.    char   path[MAXPATHLEN + 1];
  1050.  
  1051.    if (!bundle) 
  1052.    {  NXLogError("No bundle for Class %s - unable to loadImageView\n", [self name]);
  1053.       return nil;
  1054.    }
  1055.    if (![bundle getPath:path forResource:"WW3DWellImageView" ofType:"nib"])
  1056.    {  NXLogError("No path for WW3DWellImageView.nib.\n");
  1057.       return nil;
  1058.    }
  1059.    [NXApp loadNibFile:path owner:self  withNames:NO fromZone:[self zone]];
  1060.    //NXLogError ("Loaded %s.\n", path);
  1061.    [imageViewWindowList addObject:imageViewWindow];
  1062.    [imageView setImageIsShared:NO];
  1063.  
  1064.    return self;
  1065. }
  1066.  
  1067. - (BOOL)binaryRIB { return [camera binaryRIB]; }
  1068. - setBinaryRIB:(BOOL)n { [camera setBinaryRIB:n]; return [self revertControlPanel]; }
  1069. - takeBinaryRIB:sender { [camera takeBinaryRIB:sender]; return [self revertControlPanel]; }
  1070.  
  1071. - (BOOL)reuseImageView { return reuseImageView; }
  1072. - setReuseImageView:(BOOL)n { reuseImageView = n; return self; }
  1073. - takeReuseImageView:sender { reuseImageView = [sender intValue]; return self; }
  1074.  
  1075. - (BOOL)useRendribInstead { return [camera useRendribInstead]; }
  1076. - setUseRendribInstead:(BOOL)n { [camera setUseRendribInstead:n]; return [self revertControlPanel]; }
  1077. - takeUseRendribInstead:sender { [camera takeUseRendribInstead:sender]; return [self revertControlPanel]; }
  1078.  
  1079. - (BOOL)beepWhenDone { return beepWhenDone; }
  1080. - setBeepWhenDone:(BOOL)n { beepWhenDone = n; return self; }
  1081. - takeBeepWhenDone:sender { beepWhenDone = [sender intValue]; return self; }
  1082.  
  1083. - showImageView:sender
  1084. {
  1085.    if (imageView && reuseImageView)
  1086.    {  return self;
  1087.    }
  1088.    return [self loadImageView];
  1089. }
  1090.  
  1091.  
  1092. - showControlPanel:sender
  1093. {
  1094.    NXRect  scrollRect, contentRect, matrixRect;
  1095.  
  1096.  
  1097.  
  1098.   [[camera worldShape] setVisible:NO];
  1099.   // display myself so the fact that the edge is clicked is apparent...
  1100.   [self display];  NXPing();
  1101.  
  1102.   if (!wellControlPanel)
  1103.   {  id     bundle = [NXBundle bundleForClass: [self class]];
  1104.      char   path[MAXPATHLEN + 1];
  1105.  
  1106.      if (!bundle) 
  1107.      {  NXLogError("No bundle for Class %s - unable to showControlPanel\n", [self name]);
  1108.         return nil;
  1109.      }
  1110.      if (![bundle getPath:path forResource:"WW3DWellControlPanel" ofType:"nib"])
  1111.      {  NXLogError("No path for WW3DWellControlPanel.nib.\n");
  1112.         return nil;
  1113.      }
  1114.      [NXApp loadNibFile:path owner:self  withNames:NO fromZone:[self zone]];
  1115.      //NXLogError ("Loaded %s.\n", path);
  1116.      //[self display]; NXPing();
  1117.  
  1118.      // free the extra windows we brought along
  1119.      [z_infoWindow setContentView:nil];
  1120.      [z_infoWindow free];
  1121.      [z_cameraWindow setContentView:nil];
  1122.      [z_cameraWindow free];
  1123.      [z_shapeWindow setContentView:nil];
  1124.      [z_shapeWindow free];
  1125.      [z_lightWindow setContentView:nil];
  1126.      [z_lightWindow free];
  1127.      [z_tclWindow setContentView:nil];
  1128.      [z_tclWindow free];
  1129.      [z_ribWindow setContentView:nil];
  1130.      [z_ribWindow free];
  1131.  
  1132.      // our surface shader matrix needs to be put into the lower left corner of the appropriate scrollView
  1133.     
  1134.      [suParmScrollView setBorderType:NX_BEZEL];
  1135.      [suParmScrollView setVertScrollerRequired:YES];
  1136.      [suParmScrollView setHorizScrollerRequired:NO];
  1137.      [suParmScrollView setAutoresizeSubviews:YES];
  1138.      [suParmScrollView getFrame:&scrollRect];
  1139.  
  1140.      // we need to set up the docView of the ClipView to contain both
  1141.      // the Matrix that we'll stick in plus the UI objects to manipulate 
  1142.      // the args in the Matrix.
  1143.      [ScrollView getContentSize:&(contentRect.size) forFrameSize:&(scrollRect.size) horizScroller:NO vertScroller:YES borderType:NX_BEZEL];
  1144.      contentRect.origin.x = contentRect.origin.y = 0.0;
  1145.      [suParmScrollView setDocView:[[View alloc] initFrame:&contentRect]];
  1146.  
  1147.      // add the Matrix to the docView of the scrollView
  1148.      [suParmNameMatrix getFrame:&matrixRect];
  1149.      matrixRect.origin.x = matrixRect.origin.y = 0.0;
  1150.      [suParmNameMatrix setFrame:&matrixRect];
  1151.      [[suParmScrollView docView] addSubview:suParmNameMatrix];
  1152.  
  1153.      suArgViewList = [[List alloc] init];
  1154.  
  1155.      // our displacement shader matrix needs to be put into the lower left corner of the appropriate scrollView
  1156.      [diParmScrollView setBorderType:NX_BEZEL];
  1157.      [diParmScrollView setVertScrollerRequired:YES];
  1158.      [diParmScrollView setHorizScrollerRequired:NO];
  1159.      [diParmScrollView setAutoresizeSubviews:YES];
  1160.      [diParmScrollView getFrame:&scrollRect];
  1161.  
  1162.      // we need to set up the docView of the ClipView to contain both
  1163.      // the Matrix that we'll stick in plus the UI objects to manipulate 
  1164.      // the args in the Matrix.
  1165.      [ScrollView getContentSize:&(contentRect.size) forFrameSize:&(scrollRect.size) horizScroller:NO vertScroller:YES borderType:NX_BEZEL];
  1166.      contentRect.origin.x = contentRect.origin.y = 0.0;
  1167.      [diParmScrollView setDocView:[[View alloc] initFrame:&contentRect]];
  1168.  
  1169.      // add the Matrix to the docView of the scrollView
  1170.      [diParmNameMatrix getFrame:&matrixRect];
  1171.      matrixRect.origin.x = matrixRect.origin.y = 0.0;
  1172.      [diParmNameMatrix setFrame:&matrixRect];
  1173.      [[diParmScrollView docView] addSubview:diParmNameMatrix];
  1174.  
  1175.      diArgViewList = [[List alloc] init];
  1176.  
  1177.      // light inspector stuff...  
  1178.      [distantLightView setImageFile:"distantLight"];
  1179.      [distantLightView setBorderType:1];
  1180.      [distantLightView setBackgroundColor:NXConvertRGBToColor(0.373, 0.298, 0.373)]; 
  1181.      [distantLightView setBackgroundAlpha:1.0];
  1182.      [distantLightView setLightType:N3D_DistantLight];
  1183.      //[distantLightView display];
  1184.  
  1185.      [pointLightView setImageFile:"pointLight"];
  1186.      [pointLightView setBorderType:1];
  1187.      [pointLightView setBackgroundColor:NXConvertRGBToColor(0.373, 0.298, 0.373)]; 
  1188.      [pointLightView setBackgroundAlpha:1.0];
  1189.      [pointLightView setLightType:N3D_PointLight];
  1190.      //[pointLightView display];
  1191.  
  1192.      [spotLightView setImageFile:"spotLight"];
  1193.      [spotLightView setBorderType:1];
  1194.      [spotLightView setBackgroundColor:NXConvertRGBToColor(0.373, 0.298, 0.373)]; 
  1195.      [spotLightView setBackgroundAlpha:1.0];
  1196.      [spotLightView setLightType:N3D_SpotLight];
  1197.      //[spotLightView display];
  1198.  
  1199.      // shape stuff
  1200.      // red:   255 81 107 == 1.00  .318 .420 
  1201.      // green: 96 215 121 ==  .376 .843 .475
  1202.      // blue:  98 124 255 ==  .384 .486 1.00
  1203.  
  1204.      // need to set the interp input text fields so that they 
  1205.      // have the right UI behavior
  1206.      [shapeInterpTextField setNextText:shapeInterpTextField];
  1207.      [cameraInterpTextField setNextText:cameraInterpTextField];
  1208.  
  1209.      // finally, make ourselves the delegate of the wellControlPanel,
  1210.      // so that when we get a performClose:, we know to nil out the outlet...
  1211.      [wellControlPanel setDelegate:self];
  1212.   }
  1213.   [ribParser setStatusText:statusText];
  1214.   [camera setStatusText:statusText];
  1215.   [camera setCurrentShape:[camera worldShape]];
  1216.   [shapeBrowser setTitled:NO];
  1217.   [[shapeBrowser loadColumnZero] selectRootShape];
  1218.  
  1219.   // okay, revert!
  1220.   [self revertControlPanel];
  1221.   [wellControlPanel display];
  1222.   [wellControlPanel makeKeyAndOrderFront:sender];
  1223.   [[camera worldShape] setVisible:YES];
  1224.   // display myself so that we see the shape again
  1225.   [self display];  NXPing();
  1226.  
  1227.   return self;
  1228. }
  1229.  
  1230. - mouseDown:(NXEvent *)theEvent  
  1231. { edgeClicked = YES; 
  1232.   [statusText setStringValue:"loading control panel..."]; [statusText display]; NXPing();
  1233.   [self showControlPanel:nil]; 
  1234.   [statusText setStringValue:"done"]; [statusText display]; NXPing();
  1235.   return self;
  1236. }
  1237.  
  1238. - removeDefaultLights:sender { [camera removeDefaultLights]; [camera display]; return self; } 
  1239. - restoreDefaultLights:sender { [camera restoreDefaultLights]; [camera display]; return self; } 
  1240.  
  1241. - setRenderStartTime
  1242. {
  1243.   gettimeofday(&renderStartTime, 0);
  1244.   return self;
  1245. }
  1246.  
  1247. - camera:theCamera didRenderStream:(NXStream *)imageStream tag:(int)jobTag frameNumber:(int)currentFrame
  1248. {
  1249.   id           newImage;
  1250.   long         clock, tmpUsec;
  1251.   struct
  1252.       timeval  elapsedTime;
  1253.   NXRect  imageRect;
  1254.   NXSize  windowSize;
  1255.  
  1256.  
  1257.   NXLogError("camera's delegate got called for renderJobTag %d\n", jobTag);
  1258.   gettimeofday(&renderFinishTime, 0);
  1259.   time(&clock);
  1260.   sprintf(timeBuf, "rendering job %d finished at %s", jobTag, ctime(&clock));
  1261.   if (renderHistoryText)
  1262.   {  [renderHistoryText setSel:[renderHistoryText textLength] :[renderHistoryText textLength]];
  1263.      [renderHistoryText setSelGray:NX_BLACK];
  1264.      [renderHistoryText replaceSel:timeBuf];
  1265.      [renderHistoryText scrollSelToVisible];
  1266.   }
  1267.   [renderHistoryText display];
  1268.   NXPing();
  1269.  
  1270.   [self showImageView:nil];
  1271.   if (imageView)
  1272.   {  newImage = [[NXImage alloc] initFromStream:imageStream];
  1273.      [imageView setImage:newImage];
  1274.      [imageView sizeToImage:nil];
  1275.      [imageView getFrame:&imageRect];
  1276.      [[imageView superview] sizeTo:imageRect.size.width :imageRect.size.height];
  1277.      //windowSize.width = imageRect.size.width + 2;  // jeez, there must be a way to have the window do this...
  1278.      //windowSize.height = imageRect.size.height + 24;  // boy, this is really dumb...
  1279.      windowSize.width = imageRect.size.width;
  1280.      windowSize.height = imageRect.size.height;
  1281.      [imageViewWindow sizeWindow:windowSize.width :windowSize.height];
  1282.      [imageViewWindow setMinSize:&windowSize];
  1283.      [imageViewWindow setMaxSize:&windowSize];
  1284.      [imageViewWindow setTitle:[imageView name]];
  1285.      [imageView sizeToImage:nil];
  1286.      [imageViewWindow makeKeyAndOrderFront:nil];
  1287.   }
  1288.  
  1289.   elapsedTime.tv_sec = renderFinishTime.tv_sec  - renderStartTime.tv_sec;
  1290.   tmpUsec = renderFinishTime.tv_usec - renderStartTime.tv_usec;
  1291.   if (tmpUsec < 0)
  1292.   {  elapsedTime.tv_sec--;
  1293.      elapsedTime.tv_usec = (long)1000000 + tmpUsec;
  1294.   }
  1295.   else
  1296.   {  elapsedTime.tv_usec = tmpUsec;
  1297.   }
  1298.   if (elapsedTime.tv_usec > (long)1000000)
  1299.   {  elapsedTime.tv_sec++;
  1300.      elapsedTime.tv_usec -= (long)1000000;
  1301.   }
  1302.   
  1303.   sprintf(timeBuf, 
  1304.       "rendering took %d.%d seconds\n", 
  1305.       (int)(elapsedTime.tv_sec), (int)(1000000 - elapsedTime.tv_usec));
  1306.   if (renderHistoryText)
  1307.   {  [renderHistoryText setSel:[renderHistoryText textLength] :[renderHistoryText textLength]];
  1308.      [renderHistoryText setSelGray:NX_BLACK];
  1309.      [renderHistoryText replaceSel:timeBuf];
  1310.      [renderHistoryText scrollSelToVisible];
  1311.   }
  1312.   [renderHistoryText display];
  1313.   NXPing();
  1314.  
  1315.   return self;
  1316. }
  1317.  
  1318. - renderItUsing3DKit:sender
  1319. {
  1320.   long clock;
  1321.  
  1322.  
  1323.   // so here's the idea: if the camera's got a crop/selection window
  1324.   // up, we use that, otherwise we want to render the whole thing.
  1325.   //
  1326.  
  1327.   [camera setBackgroundRenderingOff];
  1328.   time(&clock);
  1329.   sprintf(timeBuf, "rendering started at %s", ctime(&clock));
  1330.   if (renderHistoryText)
  1331.   {  [renderHistoryText setSel:[renderHistoryText textLength] :[renderHistoryText textLength]];
  1332.      [renderHistoryText setSelGray:NX_BLACK];
  1333.      [renderHistoryText replaceSel:timeBuf];
  1334.   }
  1335.   [renderHistoryText display];
  1336.   NXPing();
  1337.   gettimeofday(&renderStartTime, 0);
  1338.   renderJobTag = [camera renderAsTIFF];
  1339.   NXLogError("my renderJobTag is %d\n", renderJobTag);
  1340.  
  1341.   return self;
  1342. }
  1343.  
  1344.  
  1345.  
  1346. // really should make this be the rendering command and the file be variables, so you could do something like:
  1347. // system("rsh yoshi /usr/local/prman/bin/prman /cga/tmp/foo.rib")
  1348. // actually, it should be a thread off by itself.  If Springer had made this easy in the first place, argh....
  1349.  
  1350. - renderItBlocking:sender
  1351. {
  1352.   long         clock, tmpUsec;
  1353.   struct
  1354.       timeval  elapsedTime;
  1355.   char         tmpRIBFilename[64], tmpTIFFFilename[64];
  1356.   char         cmd[128], windowTitle[256];
  1357.   //id           aRenderWrangler;
  1358.   NXRect  imageRect;
  1359.   NXSize  windowSize;
  1360.   int     ret;
  1361.  
  1362.  
  1363.   [camera setBackgroundRenderingOff];
  1364.   // so here's the idea: if the camera's got a crop/selection window
  1365.   // up, we use that, otherwise we want to render the whole thing.
  1366.   //
  1367.   sprintf(tmpRIBFilename, "/tmp/foo%d.rib", getpid());
  1368.   sprintf(tmpTIFFFilename, "/tmp/foo%d.tiff", getpid());
  1369.   [camera dumpRIBToFile:tmpRIBFilename];
  1370.   time(&clock);
  1371.   sprintf(timeBuf, "rendering started at %s", ctime(&clock));
  1372.   if (renderHistoryText)
  1373.   {  [renderHistoryText setSel:[renderHistoryText textLength] :[renderHistoryText textLength]];
  1374.      [renderHistoryText setSelGray:NX_BLACK];
  1375.      [renderHistoryText replaceSel:timeBuf];
  1376.      [renderHistoryText scrollSelToVisible];
  1377.   }
  1378.   [renderHistoryText display];
  1379.   NXPing();
  1380.   gettimeofday(&renderStartTime, 0);
  1381.  
  1382.   if ([self useRendribInstead])
  1383.   {  sprintf(cmd, "rendrib %s", tmpRIBFilename);
  1384.   }
  1385.   else
  1386.   {  sprintf(cmd, "/usr/prman/prman %s", tmpRIBFilename);
  1387.   }
  1388.  
  1389.   ret = system(cmd);
  1390.   if (ret)
  1391.   {  sprintf(timeBuf, "rendering finished at %s\nwith an error of %d (check Workspace's Console for more details.\n", ctime(&clock), ret);
  1392.      if (renderHistoryText)
  1393.      {  [renderHistoryText setSel:[renderHistoryText textLength] :[renderHistoryText textLength]];
  1394.         [renderHistoryText setSelColor:NX_COLORRED];
  1395.         [renderHistoryText replaceSel:timeBuf];
  1396.         [renderHistoryText scrollSelToVisible];
  1397.      }
  1398.      [renderHistoryText display];
  1399.      NXBeep(); NXBeep();
  1400.      NXPing();
  1401.      return nil;
  1402.   }
  1403.  
  1404.   //aRenderWrangler = [[WWRenderWrangler alloc] init];
  1405.   //[aRenderWrangler setCmd:cmd];
  1406.   //[aRenderWrangler setBoss:self];
  1407.   //cthread_detach(cthread_fork(renderItDude, aRenderWrangler));
  1408.  
  1409.   gettimeofday(&renderFinishTime, 0);
  1410.   time(&clock);
  1411.   sprintf(timeBuf, "rendering finished at %s", ctime(&clock));
  1412.   if (renderHistoryText)
  1413.   {  [renderHistoryText setSel:[renderHistoryText textLength] :[renderHistoryText textLength]];
  1414.      [renderHistoryText setSelGray:NX_BLACK];
  1415.      [renderHistoryText replaceSel:timeBuf];
  1416.      [renderHistoryText scrollSelToVisible];
  1417.   }
  1418.   [renderHistoryText display];
  1419.   NXPing();
  1420.  
  1421.   elapsedTime.tv_sec = renderFinishTime.tv_sec  - renderStartTime.tv_sec;
  1422.   tmpUsec = renderFinishTime.tv_usec - renderStartTime.tv_usec;
  1423.   if (tmpUsec < 0)
  1424.   {  elapsedTime.tv_sec--;
  1425.      elapsedTime.tv_usec = (long)1000000 + tmpUsec;
  1426.   }
  1427.   else
  1428.   {  elapsedTime.tv_usec = tmpUsec;
  1429.   }
  1430.   if (elapsedTime.tv_usec > (long)1000000)
  1431.   {  elapsedTime.tv_sec++;
  1432.      elapsedTime.tv_usec -= (long)1000000;
  1433.   }
  1434.   
  1435.   // open up the proto nib with a movieView in it.
  1436.   [self showImageView:nil];
  1437.  
  1438.   [imageView setImage:[[NXImage alloc] initFromFile:tmpTIFFFilename]];
  1439.   [imageView sizeToImage:nil];
  1440.   [imageView getFrame:&imageRect];
  1441.   [[imageView superview] sizeTo:imageRect.size.width :imageRect.size.height];
  1442.   //windowSize.width = imageRect.size.width + 2;  // jeez, there must be a way to have the window do this...
  1443.   //windowSize.height = imageRect.size.height + 24;  // boy, this is really dumb...
  1444.   windowSize.width = imageRect.size.width;
  1445.   windowSize.height = imageRect.size.height;
  1446.   [imageViewWindow sizeWindow:windowSize.width :windowSize.height];
  1447.   [imageViewWindow setMinSize:&windowSize];
  1448.   [imageViewWindow setMaxSize:&windowSize];
  1449.  
  1450.   if ([self useRendribInstead])
  1451.   {  sprintf(windowTitle, "(%d.%dsec w/rendrib)", 
  1452.         (int)(elapsedTime.tv_sec), (int)((1000000 - elapsedTime.tv_usec)/100000));
  1453.   }
  1454.   else
  1455.   {  sprintf(windowTitle, "(%d.%dsec@%3.2fshadingRate)", 
  1456.         (int)(elapsedTime.tv_sec), (int)((1000000 - elapsedTime.tv_usec)/100000), [self shadingRate]);
  1457.   }
  1458.   [imageViewWindow setTitle:windowTitle];
  1459.   [imageView sizeToImage:nil];
  1460.   [imageViewWindow makeKeyAndOrderFront:nil];
  1461.  
  1462.   sprintf(timeBuf, 
  1463.       "rendering took %d.%d seconds\n", 
  1464.       (int)(elapsedTime.tv_sec), (int)((1000000 - elapsedTime.tv_usec)/100000));
  1465.   if (renderHistoryText)
  1466.   {  [renderHistoryText setSel:[renderHistoryText textLength] :[renderHistoryText textLength]];
  1467.      [renderHistoryText setSelGray:NX_BLACK];
  1468.      [renderHistoryText replaceSel:timeBuf];
  1469.      [renderHistoryText scrollSelToVisible];
  1470.   }
  1471.   [renderHistoryText display];
  1472.   if (beepWhenDone) { NXBeep(); }
  1473.   NXPing();
  1474.   return self;
  1475. }
  1476.  
  1477. - saveImage:sender  { return [camera saveImage:sender]; }
  1478.  
  1479. - dumpRIB:sender  { return [camera dumpRIB:sender]; }
  1480.  
  1481. - dumpShot:sender  { return [camera dumpShotToRIB:sender]; }
  1482.  
  1483. - dumpEve:sender  { return [camera dumpEve:sender]; }
  1484.  
  1485. - dumpScene:sender  { return [camera dumpScene:sender]; }
  1486.  
  1487. - dump3DTextScene:sender  { return [camera dump3DTextScene:sender]; }
  1488.  
  1489. - dumpInventor:sender  { return [camera dumpInventor:sender]; }
  1490.  
  1491. - dumpSceneGraph:sender
  1492. {
  1493.   // this one, I'm gonna do
  1494.  
  1495.   // First of all, we need to find out the "oldest" sample in the current scene.
  1496.   //  
  1497.  
  1498.   return self;
  1499. }
  1500.  
  1501.  
  1502. // really should make this be the rendering command and the file be variables, so you could do something like:
  1503. // system("rsh yoshi /usr/local/prman/bin/prman /cga/tmp/foo.rib")
  1504.  
  1505. - renderShotBlocking:sender
  1506. {
  1507.   long         clock, tmpUsec;
  1508.   struct
  1509.       timeval  elapsedTime;
  1510.   char         tmpAnimDir[128], tmpRIBFilename[128];
  1511.   char         cmd[128];
  1512.  
  1513.  
  1514.   [camera setBackgroundRenderingOff];
  1515.   // so here's the idea: if the camera's got a crop/selection window
  1516.   // up, we use that, otherwise we want to render the whole thing.
  1517.   //
  1518.   sprintf(tmpAnimDir, "/tmp/foo%d.anim", getpid());
  1519.   sprintf(cmd, "mkdirs %s", tmpAnimDir);
  1520.   system(cmd);
  1521.   sprintf(tmpRIBFilename, "%s/foo%d.rib", tmpAnimDir, getpid());
  1522.   [camera dumpShotToRIBFile:tmpRIBFilename];
  1523.   time(&clock);
  1524.   sprintf(timeBuf, "rendering started at %s", ctime(&clock));
  1525.   if (renderHistoryText)
  1526.   {  [renderHistoryText setSel:[renderHistoryText textLength] :[renderHistoryText textLength]];
  1527.      [renderHistoryText setSelGray:NX_BLACK];
  1528.      [renderHistoryText replaceSel:timeBuf];
  1529.      [renderHistoryText scrollSelToVisible];
  1530.   }
  1531.   [renderHistoryText display];
  1532.   NXPing();
  1533.   gettimeofday(&renderStartTime, 0);
  1534.  
  1535.   sprintf(cmd, "/usr/prman/prman %s", tmpRIBFilename);
  1536.  
  1537.  
  1538.   // at this point, we want to fork a thread to actually render this guy.
  1539.  
  1540.   system(cmd);
  1541.   //cthread_detach(cthread_fork(evalCmdUsingSystem, cmd));
  1542.  
  1543.  
  1544.   gettimeofday(&renderFinishTime, 0);
  1545.   time(&clock);
  1546.   sprintf(timeBuf, "rendering finished at %s", ctime(&clock));
  1547.   if (renderHistoryText)
  1548.   {  [renderHistoryText setSel:[renderHistoryText textLength] :[renderHistoryText textLength]];
  1549.      [renderHistoryText setSelGray:NX_BLACK];
  1550.      [renderHistoryText replaceSel:timeBuf];
  1551.      [renderHistoryText scrollSelToVisible];
  1552.   }
  1553.   [renderHistoryText display];
  1554.   NXPing();
  1555.   [self showImageView:nil];
  1556.   [imageView setAnimDir:tmpAnimDir];
  1557.  
  1558.   elapsedTime.tv_sec = renderFinishTime.tv_sec  - renderStartTime.tv_sec;
  1559.   tmpUsec = renderFinishTime.tv_usec - renderStartTime.tv_usec;
  1560.   if (tmpUsec < 0)
  1561.   {  elapsedTime.tv_sec--;
  1562.      elapsedTime.tv_usec = (long)1000000 + tmpUsec;
  1563.   }
  1564.   else
  1565.   {  elapsedTime.tv_usec = tmpUsec;
  1566.   }
  1567.   if (elapsedTime.tv_usec > (long)1000000)
  1568.   {  elapsedTime.tv_sec++;
  1569.      elapsedTime.tv_usec -= (long)1000000;
  1570.   }
  1571.   
  1572.   sprintf(timeBuf, 
  1573.       "rendering took %d.%d seconds\n", 
  1574.       (int)(elapsedTime.tv_sec), (int)(1000000 - elapsedTime.tv_usec));
  1575.   if (renderHistoryText)
  1576.   {  [renderHistoryText setSel:[renderHistoryText textLength] :[renderHistoryText textLength]];
  1577.      [renderHistoryText setSelGray:NX_BLACK];
  1578.      [renderHistoryText replaceSel:timeBuf];
  1579.      [renderHistoryText scrollSelToVisible];
  1580.   }
  1581.   [renderHistoryText display];
  1582.   NXPing();
  1583.   return self;
  1584. }
  1585.  
  1586. //
  1587. - addShape:sender
  1588. {
  1589.   id           theOpenPanel;
  1590.   const char   *filename;
  1591.   char         *extension, 
  1592.                *filterTypes[6] = {"eve", "rib", "mdl", "wwModel", "wwScene", NULL };
  1593.  
  1594.  
  1595.   theOpenPanel = [OpenPanel new];
  1596.   [theOpenPanel allowMultipleFiles:NO];
  1597.   if (![theOpenPanel runModalForTypes:filterTypes])
  1598.   {  return nil;
  1599.   }
  1600.  
  1601.   filename = [theOpenPanel filename];
  1602.   extension = (char *)filename + (strlen(filename) - 4);
  1603.   if ((filename) && (!strcmp(".rib", extension)))
  1604.   {  [self addToShapeHierarchyFromRIBFile:filename];
  1605.   }
  1606.   if ((filename) && (!strcmp(".eve",  extension)))
  1607.   {  [self addToShapeHierarchyFromEveFile:filename];
  1608.   }
  1609.   if ((filename) && (!strcmp(".mdl",  extension)))
  1610.   {  [self addToShapeHierarchyFromMdlFile:filename];
  1611.   }
  1612.  
  1613.   extension = (char *)filename + (strlen(filename) - 8);
  1614.   if ((filename) && (!strcmp(".wwModel",  extension)))
  1615.   {  [self addToShapeHierarchyFromMdlFile:filename];
  1616.   }
  1617.   if ((filename) && (!strcmp(".wwScene",  extension)))
  1618.   {  [self addToShapeHierarchyFromSceneFile:filename];
  1619.   }
  1620.   return self;
  1621. }
  1622. //
  1623. - replaceWorldShape:sender
  1624. {
  1625.   id           theOpenPanel;
  1626.   const char   *filename;
  1627.   char         *extension, 
  1628.                *filterTypes[6] = {"eve", "rib", "mdl", "wwModel", "wwScene", NULL };
  1629.  
  1630.  
  1631.   theOpenPanel = [OpenPanel new];
  1632.   [theOpenPanel allowMultipleFiles:NO];
  1633.   if (![theOpenPanel runModalForTypes:filterTypes])
  1634.   {  return nil;
  1635.   }
  1636.  
  1637.   filename = [theOpenPanel filename];
  1638.   extension = (char *)filename + (strlen(filename) - 4);
  1639.   if ((filename) && (!strcmp(".rib", extension)))
  1640.   {  [self buildNewShapeHierarchyFromRIBFile:filename];
  1641.   }
  1642.   if ((filename) && (!strcmp(".eve",  extension)))
  1643.   {  [self buildNewShapeHierarchyFromEveFile:filename];
  1644.   }
  1645.   if ((filename) && (!strcmp(".mdl",  extension)))
  1646.   {  [self buildNewShapeHierarchyFromMdlFile:filename];
  1647.   }
  1648.  
  1649.   extension = (char *)filename + (strlen(filename) - 8);
  1650.   if ((filename) && (!strcmp(".wwModel",  extension)))
  1651.   {  [self addToShapeHierarchyFromMdlFile:filename];
  1652.   }
  1653.   if ((filename) && (!strcmp(".wwScene",  extension)))
  1654.   {  [self addToShapeHierarchyFromSceneFile:filename];
  1655.   }
  1656.  
  1657.   return self;
  1658. }
  1659.  
  1660. - loadNibForModelInterp:(const char *)nibFilename  
  1661. {  return [[ribParser tclInterp] loadControlPanel:(char *)nibFilename modally:NO];
  1662. }
  1663.  
  1664. - loadNibForCameraInterp:(const char *)nibFilename  
  1665. {  return [[camera tclInterp] loadControlPanel:(char *)nibFilename modally:NO];
  1666. }
  1667.  
  1668. - revertSurfaceShaderInspectorFor:s
  1669. {
  1670.   int       i, howManyCells, howManyArgs;
  1671.   RtPoint   pValue;
  1672.   float     fValue;
  1673.   NXColor   cValue;
  1674.   char      *sValue;
  1675.   SLO_TYPE  argType, shaderType;
  1676.   id        newCell, newArgView;
  1677.   NXRect    argViewFrame, matrixFrame, superFrame;
  1678.   NXSize    cellSize, intercellSize;
  1679.  
  1680.  
  1681.   howManyArgs = [s shaderArgCount];
  1682.   shaderType = [s shaderType];
  1683.  
  1684.   [suNameText setStringValue:[s shader]];  
  1685.  
  1686.   // get the scrollView's docView
  1687.   // need to make a  
  1688.   suParmView = [suParmScrollView docView];
  1689.  
  1690.   [suParmNameMatrix setAutoscroll:YES];
  1691.   [suParmNameMatrix setScrollable:YES];
  1692.   
  1693.   [suParmNameMatrix getFrame:&matrixFrame];
  1694.   [suParmNameMatrix getCellSize:&cellSize];
  1695.   [suParmNameMatrix getIntercell:&intercellSize];
  1696.   // don't want any intercell spacing between arg views
  1697.   argViewFrame.size.width =  cellSize.width - 1;
  1698.   argViewFrame.size.height =  cellSize.height + intercellSize.height;
  1699.   argViewFrame.origin.x =  matrixFrame.size.width; 
  1700.   argViewFrame.origin.y =  (howManyArgs - 1) * argViewFrame.size.height;
  1701.  
  1702.   // clear things out...
  1703.   howManyCells = [[suParmNameMatrix cellList] count];
  1704.   for (i = 0; i < howManyCells; i++)
  1705.   {  [suParmNameMatrix removeRowAt:0 andFree:YES];
  1706.      [suParmNameMatrix sizeToCells];
  1707.   }
  1708.   [suArgViewList freeObjects];
  1709.  
  1710.   // need to tell the Matrix's superview to resize itself to (howManyArgs*argViewFrame.size.height)
  1711.   [[suParmNameMatrix superview] getFrame:&superFrame];
  1712.   [[suParmNameMatrix superview] sizeTo:superFrame.size.width :(howManyArgs*argViewFrame.size.height)];
  1713.  
  1714.   for (i = 0; i < howManyArgs; i++)
  1715.   {  // build up the new one...
  1716.      [suParmNameMatrix addRow];
  1717.      [suParmNameMatrix sizeToCells];
  1718.      newCell = [suParmNameMatrix cellAt:i :0];
  1719.      [newCell setStringValue:[s shaderArgNameAt:i]];
  1720.      [newCell setAlignment:NX_RIGHTALIGNED];
  1721.  
  1722.      // now we need to build up the args...
  1723.      argType = [s shaderArgType:[s shaderArgNameAt:i]];
  1724.      switch (argType) {
  1725.      case SLO_TYPE_POINT:   [s getShaderArg:[s shaderArgNameAt:i] pointValue:&pValue];
  1726.                                 NXLogError("\targName:%s type:point value:(%f %f %f)\n", 
  1727.                                            [s shaderArgNameAt:i], N3D_XComp(pValue), N3D_YComp(pValue), N3D_ZComp(pValue)); 
  1728.                                 break;
  1729.      case SLO_TYPE_COLOR:   [s getShaderArg:[s shaderArgNameAt:i] colorValue:&cValue];
  1730.                                 newArgView = [[WWShaderArgColorWell alloc] initFrame:&argViewFrame];
  1731.                                 [newArgView setShaderArgName:[s shaderArgNameAt:i]];
  1732.                                 [newArgView setTarget:s];
  1733.                                 [newArgView setAction:@selector(takeColorArg:)];
  1734.                                 [newArgView setColor:cValue];
  1735.                                 [suParmView addSubview:newArgView];
  1736.                                 [suArgViewList addObject:newArgView];
  1737.                                 break;
  1738.      case SLO_TYPE_SCALAR:  [s getShaderArg:[s shaderArgNameAt:i] floatValue:&fValue];
  1739.                                 newArgView = [[WWShaderArgTextField alloc] initFrame:&argViewFrame];
  1740.                                 [newArgView setShaderArgName:[s shaderArgNameAt:i]];
  1741.                                 [newArgView setTarget:s];
  1742.                                 [newArgView setAction:@selector(takeFloatArg:)];
  1743.                                 [newArgView setFloatValue:fValue];
  1744.                                 [suParmView addSubview:newArgView];
  1745.                                 [suArgViewList addObject:newArgView];
  1746.                                 break;
  1747.      case SLO_TYPE_STRING:  [s getShaderArg:[s shaderArgNameAt:i] stringValue:&sValue];
  1748.                                 newArgView = [[WWShaderArgTextField alloc] initFrame:&argViewFrame];
  1749.                                 [newArgView setShaderArgName:[s shaderArgNameAt:i]];
  1750.                                 [newArgView setTarget:s];
  1751.                                 [newArgView setAction:@selector(takeStringArg:)];
  1752.                                 [newArgView setStringValue:sValue];
  1753.                                 [suParmView addSubview:newArgView];
  1754.                                 [suArgViewList addObject:newArgView];
  1755.                                 break;
  1756.      default:               NXLogError("\targName:%s type:UNKNOWN\n", [s shaderArgNameAt:i]);
  1757.                                 break;
  1758.       }
  1759.       argViewFrame.origin.y -=  argViewFrame.size.height;
  1760.   }
  1761.   [suParmView display];
  1762.  
  1763.   
  1764.  
  1765.   return self;
  1766. }
  1767.  
  1768. - revertDisplacementShaderInspectorFor:s
  1769. {
  1770.   int       i, howManyCells, howManyArgs;
  1771.   RtPoint   pValue;
  1772.   float     fValue;
  1773.   NXColor   cValue;
  1774.   char      *sValue;
  1775.   SLO_TYPE  argType, shaderType;
  1776.   id        newCell, newArgView;
  1777.   NXRect    argViewFrame, matrixFrame, superFrame;
  1778.   NXSize    cellSize, intercellSize;
  1779.  
  1780.  
  1781.   howManyArgs = [s shaderArgCount];
  1782.   shaderType = [s shaderType];
  1783.  
  1784.   [diNameText setStringValue:[s shader]];  
  1785.  
  1786.   // get the scrollView's docView
  1787.   // need to make a  
  1788.   diParmView = [diParmScrollView docView];
  1789.  
  1790.   [diParmNameMatrix setAutoscroll:YES];
  1791.   [diParmNameMatrix setScrollable:YES];
  1792.   
  1793.   [diParmNameMatrix getFrame:&matrixFrame];
  1794.   [diParmNameMatrix getCellSize:&cellSize];
  1795.   [diParmNameMatrix getIntercell:&intercellSize];
  1796.   // don't want any intercell spacing between arg views
  1797.   argViewFrame.size.width =  cellSize.width - 1;
  1798.   argViewFrame.size.height =  cellSize.height + intercellSize.height;
  1799.   argViewFrame.origin.x =  matrixFrame.size.width; 
  1800.   argViewFrame.origin.y =  (howManyArgs - 1) * argViewFrame.size.height;
  1801.  
  1802.   // clear things out...
  1803.   howManyCells = [[diParmNameMatrix cellList] count];
  1804.   for (i = 0; i < howManyCells; i++)
  1805.   {  [diParmNameMatrix removeRowAt:0 andFree:YES];
  1806.      [diParmNameMatrix sizeToCells];
  1807.   }
  1808.   [diArgViewList freeObjects];
  1809.  
  1810.   // need to tell the Matrix's superview to resize itself to (howManyArgs*argViewFrame.size.height)
  1811.   [[diParmNameMatrix superview] getFrame:&superFrame];
  1812.   [[diParmNameMatrix superview] sizeTo:superFrame.size.width :(howManyArgs*argViewFrame.size.height)];
  1813.  
  1814.   for (i = 0; i < howManyArgs; i++)
  1815.   {  // build up the new one...
  1816.      [diParmNameMatrix addRow];
  1817.      [diParmNameMatrix sizeToCells];
  1818.      newCell = [diParmNameMatrix cellAt:i :0];
  1819.      [newCell setStringValue:[s shaderArgNameAt:i]];
  1820.      [newCell setAlignment:NX_RIGHTALIGNED];
  1821.  
  1822.      // now we need to build up the args...
  1823.      argType = [s shaderArgType:[s shaderArgNameAt:i]];
  1824.      switch (argType) {
  1825.      case SLO_TYPE_POINT:   [s getShaderArg:[s shaderArgNameAt:i] pointValue:&pValue];
  1826.                                 NXLogError("\targName:%s type:point value:(%f %f %f)\n", 
  1827.                                            [s shaderArgNameAt:i], N3D_XComp(pValue), N3D_YComp(pValue), N3D_ZComp(pValue)); 
  1828.                                 break;
  1829.      case SLO_TYPE_COLOR:   [s getShaderArg:[s shaderArgNameAt:i] colorValue:&cValue];
  1830.                                 newArgView = [[WWShaderArgColorWell alloc] initFrame:&argViewFrame];
  1831.                                 [newArgView setShaderArgName:[s shaderArgNameAt:i]];
  1832.                                 [newArgView setTarget:s];
  1833.                                 [newArgView setAction:@selector(takeColorArg:)];
  1834.                                 [newArgView setColor:cValue];
  1835.                                 [diParmView addSubview:newArgView];
  1836.                                 [diArgViewList addObject:newArgView];
  1837.                                 break;
  1838.      case SLO_TYPE_SCALAR:  [s getShaderArg:[s shaderArgNameAt:i] floatValue:&fValue];
  1839.                                 newArgView = [[WWShaderArgTextField alloc] initFrame:&argViewFrame];
  1840.                                 [newArgView setShaderArgName:[s shaderArgNameAt:i]];
  1841.                                 [newArgView setTarget:s];
  1842.                                 [newArgView setAction:@selector(takeFloatArg:)];
  1843.                                 [newArgView setFloatValue:fValue];
  1844.                                 [diParmView addSubview:newArgView];
  1845.                                 [diArgViewList addObject:newArgView];
  1846.                                 break;
  1847.      case SLO_TYPE_STRING:  [s getShaderArg:[s shaderArgNameAt:i] stringValue:&sValue];
  1848.                                 newArgView = [[WWShaderArgTextField alloc] initFrame:&argViewFrame];
  1849.                                 [newArgView setShaderArgName:[s shaderArgNameAt:i]];
  1850.                                 [newArgView setTarget:s];
  1851.                                 [newArgView setAction:@selector(takeStringArg:)];
  1852.                                 [newArgView setStringValue:sValue];
  1853.                                 [diParmView addSubview:newArgView];
  1854.                                 [diArgViewList addObject:newArgView];
  1855.                                 break;
  1856.      default:               NXLogError("\targName:%s type:UNKNOWN\n", [s shaderArgNameAt:i]);
  1857.                                 break;
  1858.       }
  1859.       argViewFrame.origin.y -=  argViewFrame.size.height;
  1860.   }
  1861.   [diParmView display];
  1862.  
  1863.   return self;
  1864. }
  1865.  
  1866. - takeSuColor:sender
  1867. {
  1868.   [[[camera currentShape] shaderType:SLO_TYPE_SURFACE] setColor:[sender color]];
  1869.   return self;
  1870. }
  1871.  
  1872. - takeDiColor:sender
  1873. {
  1874.   [[[camera currentShape] shaderType:SLO_TYPE_DISPLACEMENT] setColor:[sender color]];
  1875.   return self;
  1876. }
  1877.  
  1878. - drawRtMatrix:(RtMatrix)anRtMatrix inMatrix:aMatrix
  1879. {
  1880.   int  i, j;
  1881.  
  1882.  
  1883.   for (i = 0; i < 4; i++)
  1884.   {  for (j = 0; j < 4; j++)
  1885.      {  [[aMatrix cellAt:i :j] setFloatValue:anRtMatrix[i][j]];
  1886.      }
  1887.   }
  1888.   return self;
  1889. }
  1890.  
  1891. - fillRIBCommandsMatrix:theMatrix
  1892. {
  1893.    int         howMany, i;
  1894.    id          newCell;
  1895.    const char  *className;
  1896.  
  1897.  
  1898.    howMany = [[theMatrix cellList] count];
  1899.    for (i = 0; i < howMany; i++)
  1900.    {  [theMatrix removeRowAt:0 andFree:YES];
  1901.       [theMatrix sizeToCells];
  1902.    }
  1903.    howMany = [[[camera currentShape] ribCommands] count];
  1904.    for (i = 0; i < howMany; i++)
  1905.    {  [theMatrix addRow];
  1906.       [theMatrix sizeToCells];
  1907.       newCell = [theMatrix cellAt:i :0];
  1908. //Note: these really should be double-clickable themselves...
  1909.       // need to find out the class name of the cell
  1910.       // if it's an EveCommand, we need to get the class name of the firstSample
  1911.       // we'll enclose that in ()
  1912.       // if it's an EveProc, we need to get the name of the proc
  1913.       // we'll enclose that in {}
  1914.       className = [[[[[camera currentShape] ribCommands] objectAt:i] class] name];
  1915.       if (!strcmp(className, "EveCommand") || !strcmp(className, "EveProc"))
  1916.       {  className = [[[[camera currentShape] ribCommands] objectAt:i] sampleName];
  1917.       }
  1918.       [newCell setStringValue:className];
  1919.    }
  1920.  
  1921.    return self;
  1922. }
  1923.  
  1924. //
  1925. - removeSurfaceShader:sender 
  1926.    [[camera currentShape] removeSurfaceShader:sender]; 
  1927.    [self revertSurfaceShaderInspectorFor:nil];
  1928.    [delegate sceneWasUpdated:camera];
  1929.    [self display];
  1930.    return self;
  1931. }
  1932.  
  1933. - removeDisplacementShader:sender 
  1934.    [[camera currentShape] removeDisplacementShader:sender]; 
  1935.    [self revertDisplacementShaderInspectorFor:nil];
  1936.    [delegate sceneWasUpdated:camera];
  1937.    [self display];
  1938.    return self;
  1939. }
  1940.  
  1941. - addShader:sender
  1942. {
  1943.   id           theOpenPanel;
  1944.   const char   *filename;
  1945.   char         *extension, 
  1946.                *filterTypes[3] = {"slo", "WW3DShader", NULL };
  1947.   id            newShader;
  1948.   static char   shaderName[256];
  1949.  
  1950.  
  1951.   theOpenPanel = [OpenPanel new];
  1952.   [theOpenPanel allowMultipleFiles:NO];
  1953.   if (![theOpenPanel runModalForDirectory:"/LocalLibrary/Shaders" file:NULL types:filterTypes])
  1954.   {  return self;
  1955.   }
  1956.  
  1957.   filename = [theOpenPanel filename];
  1958.   extension = (char *)filename + (strlen(filename) - 4);
  1959.   if ((filename) && (!strcmp(".slo",  extension)))
  1960.   {  basename(filename, ".slo", shaderName);
  1961.      if ((newShader = [(WW3DShader *)[[WW3DShader alloc] init] setShader:shaderName]))
  1962.      {  [[camera currentShape] setShader_:newShader];
  1963.      }
  1964.  
  1965.      // at this point, we want to ask the shader to describe its
  1966.      // arguments to us, and construct an inspector for it which gets put on
  1967.      // it the control panel
  1968.      if ([newShader shaderType] == SLO_TYPE_SURFACE)
  1969.      {  [self revertSurfaceShaderInspectorFor:newShader];
  1970.      }
  1971.      if ([newShader shaderType] == SLO_TYPE_DISPLACEMENT)
  1972.      {  [self revertDisplacementShaderInspectorFor:newShader];
  1973.      }
  1974.  
  1975.      [delegate sceneWasUpdated:camera];
  1976.      [self display];
  1977.   }
  1978.   else
  1979.   {  return nil;
  1980.   }
  1981.   return self;
  1982. }
  1983.  
  1984. - addSurfaceShader:sender
  1985. {
  1986.   id           theOpenPanel;
  1987.   const char   *filename;
  1988.   char         *extension, 
  1989.                *filterTypes[3] = {"slo", "WW3DShader", NULL };
  1990.   id            newShader;
  1991.   static char   shaderName[256];
  1992.  
  1993.  
  1994.   theOpenPanel = [OpenPanel new];
  1995.   [theOpenPanel allowMultipleFiles:NO];
  1996.   if (![theOpenPanel runModalForDirectory:"/LocalLibrary/Shaders" file:NULL types:filterTypes])
  1997.   {  return self;
  1998.   }
  1999.  
  2000.   filename = [theOpenPanel filename];
  2001.   extension = (char *)filename + (strlen(filename) - 4);
  2002.   if ((filename) && (!strcmp(".slo",  extension)))
  2003.   {  basename(filename, ".slo", shaderName);
  2004.      if (!(newShader = [(WW3DShader *)[[WW3DShader alloc] init] setShader:shaderName]))
  2005.      {  return nil;
  2006.      }
  2007.  
  2008.      // at this point, we want to ask the shader to describe its
  2009.      // arguments to us, and construct an inspector for it which gets put on
  2010.      // it the control panel
  2011.      if ([newShader shaderType] == SLO_TYPE_SURFACE)
  2012.      {  [[camera currentShape] setShader_:newShader];
  2013.         [self revertSurfaceShaderInspectorFor:newShader];
  2014.         [delegate sceneWasUpdated:camera];
  2015.         [self display];
  2016.      }
  2017.      else
  2018.      {  NXLogError("%s is not a surface shader\n", shaderName);
  2019.     [newShader free];
  2020.     return nil;
  2021.      }
  2022.   }
  2023.   else
  2024.   {  return nil;
  2025.   }
  2026.   return self;
  2027. }
  2028.  
  2029. - addDisplacementShader:sender
  2030. {
  2031.   id           theOpenPanel;
  2032.   const char   *filename;
  2033.   char         *extension, 
  2034.                *filterTypes[3] = {"slo", "WW3DShader", NULL };
  2035.   id            newShader;
  2036.   static char   shaderName[256];
  2037.  
  2038.  
  2039.   theOpenPanel = [OpenPanel new];
  2040.   [theOpenPanel allowMultipleFiles:NO];
  2041.   if (![theOpenPanel runModalForDirectory:"/LocalLibrary/Shaders" file:NULL types:filterTypes])
  2042.   {  return self;
  2043.   }
  2044.  
  2045.   filename = [theOpenPanel filename];
  2046.   extension = (char *)filename + (strlen(filename) - 4);
  2047.   if ((filename) && (!strcmp(".slo",  extension)))
  2048.   {  basename(filename, ".slo", shaderName);
  2049.      if (!(newShader = [(WW3DShader *)[[WW3DShader alloc] init] setShader:shaderName]))
  2050.      {  return nil;
  2051.      }
  2052.  
  2053.      // at this point, we want to ask the shader to describe its
  2054.      // arguments to us, and construct an inspector for it which gets put on
  2055.      // it the control panel
  2056.      if ([newShader shaderType] == SLO_TYPE_DISPLACEMENT)
  2057.      {  [[camera currentShape] setShader_:newShader];
  2058.         [self revertDisplacementShaderInspectorFor:newShader];
  2059.         [delegate sceneWasUpdated:camera];
  2060.         [self display];
  2061.      }
  2062.      else
  2063.      {  NXLogError("%s is not a displacement shader\n", shaderName);
  2064.     [newShader free];
  2065.     return nil;
  2066.      }
  2067.   }
  2068.   else
  2069.   {  return nil;
  2070.   }
  2071.   return self;
  2072. }
  2073.  
  2074.  
  2075. // inspector/control panel methods
  2076. //
  2077. - (RtFloat)tesselation  { return [camera tesselation]; }
  2078. - takeTesselation:sender  { [camera takeTesselation:sender];  return [self revertControlPanel]; }
  2079. //
  2080. - (NXColor)backgroundColor  { return [camera backgroundColor]; }
  2081. - takeWellBackgroundColor:sender  { [camera setBackgroundColor:[sender color]];  return [self revertControlPanel]; }
  2082. //
  2083. - (RtFloat)lowRezTesselation  { return [camera lowRezTesselation]; }
  2084. - takeLowRezTesselation:sender  {  [camera takeLowRezTesselation:sender];   return [self revertControlPanel]; }
  2085. //
  2086. - (RtFloat)shadingRate { return [camera shadingRate]; }
  2087. // don't bother reverting the control panel for this one
  2088. - takeShadingRate:sender 
  2089. {  [camera takeShadingRate:sender]; 
  2090.    [delegate sceneWasUpdated:camera]; 
  2091.    // rather than revert the whole control panel, just do these two...
  2092.    [shadingRateText setFloatValue:[camera shadingRate]];
  2093.    [shadingRateSlider setFloatValue:[camera shadingRate]];
  2094.    return self; 
  2095. }
  2096. //
  2097. - (BOOL)firmTransforms {  return [ribParser firmTransforms]; }
  2098. - takeFirmTransforms:sender {  [ribParser takeFirmTransforms:sender];  return [self revertControlPanel]; }
  2099. //
  2100. - (BOOL)ignoreShadingRate { return [ribParser ignoreShadingRate]; } 
  2101. - takeIgnoreShadingRate:sender { [ribParser setIgnoreShadingRate:sender];  return [self revertControlPanel]; }
  2102. //
  2103. - (BOOL)ignoreColors { return [ribParser ignoreColors]; } 
  2104. - takeIgnoreColors:sender { [ribParser setIgnoreColors:sender];  return [self revertControlPanel]; }
  2105. //
  2106. - (BOOL)ignoreShaders { return [ribParser ignoreShaders]; }
  2107. - takeIgnoreShaders:sender { [ribParser setIgnoreShaders:sender];  return [self revertControlPanel]; }
  2108. //
  2109. - (BOOL)ignoreLights { return [ribParser ignoreLights]; }
  2110. - takeIgnoreLights:sender { [ribParser setIgnoreLights:sender];  return [self revertControlPanel]; }
  2111. //
  2112. - (NXColor)selectedColor { return selectedColor; }
  2113. - takeSelectedColor:sender { return self; }
  2114. //
  2115. - (NXColor)unselectedColor { return unselectedColor; }
  2116. - takeUnselectedColor:sender { return self; }
  2117. //
  2118. - (float)fov { return [camera fieldOfView]; }
  2119. - takeFOV:sender 
  2120. { float fov = [sender floatValue];
  2121.  
  2122.   if (fov < 0.0)
  2123.   {  fov = 0.0;
  2124.   }
  2125.   if (fov > 180.0)
  2126.   {  fov = 180.0;
  2127.   }
  2128.   [camera setFieldOfViewByAngle:fov]; 
  2129.   [self revertControlPanel];
  2130.   [delegate sceneWasUpdated:camera]; 
  2131.   [self display];
  2132.   return self; 
  2133. }
  2134. //
  2135. - (int)aspectRatioType { return aspectRatioType; }
  2136. - (float)aspectRatio { return aspectRatio; }
  2137. - setCustomAspectRatioText:newCustomAspectRatioText { customAspectRatioText = newCustomAspectRatioText; return self; }
  2138. - takeAspectRatioFromMatrix:sender
  2139. {
  2140.   NXRect  newRect;
  2141.  
  2142.  
  2143.   [self getFrame:&newRect];
  2144.   aspectRatioType = [[sender selectedCell] tag];
  2145.   switch (aspectRatioType)
  2146.   {  case WW_ASPECT_DONT_CARE:
  2147.             [customAspectRatioText setEnabled:NO];
  2148.             break;
  2149.      case WW_ASPECT_NTSC:  // 1.33:1
  2150.             [customAspectRatioText setEnabled:NO];
  2151.             newRect.size.height = newRect.size.width/1.33;
  2152.             break;
  2153.      case WW_ASPECT_AMERICAN_WIDESCREEN:  // 1.85:1
  2154.             [customAspectRatioText setEnabled:NO];
  2155.             newRect.size.height = newRect.size.width/1.85;
  2156.             break;
  2157.      case WW_ASPECT_EUROPEAN_WIDESCREEN:  // 1.66:1
  2158.             [customAspectRatioText setEnabled:NO];
  2159.             newRect.size.height = newRect.size.width/1.66;
  2160.             break;
  2161.      case WW_ASPECT_VISTA_VISION:  // 2.21:1
  2162.             [customAspectRatioText setEnabled:NO];
  2163.             newRect.size.height = newRect.size.width/2.21;
  2164.             break;
  2165.      case WW_ASPECT_SQUARE:  // 1:1
  2166.             [customAspectRatioText setEnabled:NO];
  2167.             if (newRect.size.width < newRect.size.height)
  2168.             {  newRect.size.height = newRect.size.width;
  2169.         }
  2170.         else
  2171.         {  newRect.size.width = newRect.size.height;
  2172.         }
  2173.             break;
  2174.      case WW_ASPECT_CUSTOM:  //aspectX:aspectY
  2175.             [customAspectRatioText setEnabled:YES];
  2176.             aspectRatio = [customAspectRatioText floatValue];
  2177.             if (aspectRatio < 1.0)
  2178.         {  newRect.size.width = newRect.size.height * aspectRatio;
  2179.         }
  2180.         else
  2181.         {  newRect.size.height = newRect.size.width/aspectRatio;
  2182.         }
  2183.             break;
  2184.      default:
  2185.             [customAspectRatioText setEnabled:NO];
  2186.             NXLogError("unknown aspect ratio type: %d", aspectRatioType);
  2187.             break;
  2188.   }
  2189.   [self sizeTo:newRect.size.width :newRect.size.height];
  2190.   [delegate sceneWasUpdated:camera]; 
  2191.   [self revertControlPanel];
  2192.  
  2193.   return self;
  2194. }
  2195. //
  2196. - takeAspectRatio:sender
  2197. {
  2198.   NXRect  newRect;
  2199.  
  2200.  
  2201.   [self getFrame:&newRect];
  2202.   aspectRatio = [sender floatValue];
  2203.  
  2204.   if (aspectRatioType != WW_ASPECT_CUSTOM)
  2205.   {  [self revertControlPanel];
  2206.      return self;
  2207.   }
  2208.   if (aspectRatio < 1.0)
  2209.   {  newRect.size.width = newRect.size.height * aspectRatio;
  2210.   }
  2211.   else
  2212.   {  newRect.size.height = newRect.size.width/aspectRatio;
  2213.   }
  2214.   [self sizeTo:newRect.size.width :newRect.size.height];
  2215.   [delegate sceneWasUpdated:camera]; 
  2216.   [self revertControlPanel];
  2217.  
  2218.   return self;
  2219. }
  2220. //
  2221. - (N3DProjectionType)projectionType { return projectionType; }
  2222. - takeProjectionTypeFromMatrix:sender
  2223. {
  2224.   int  theProjectionType = [[sender selectedCell] tag];
  2225.  
  2226.  
  2227.   switch (theProjectionType)
  2228.   {  case N3D_Perspective:
  2229.             projectionType = theProjectionType;
  2230.             break;
  2231.      case N3D_Orthographic:
  2232.             projectionType = theProjectionType;
  2233.             break;
  2234.      default:
  2235.             NXLogError("unknown projection type: %d", theProjectionType);
  2236.             break;
  2237.   }
  2238.   [camera setProjection:projectionType];
  2239.   [delegate sceneWasUpdated:camera]; 
  2240.   [self revertControlPanel];
  2241.   [window display];
  2242.  
  2243.   return self;
  2244. }
  2245.  
  2246. - takeInitialGeometry:sender
  2247. {
  2248.   char *name = (char *)[sender stringValue], *extension;
  2249.  
  2250.   
  2251.   // must be at least x.rib or x.eve
  2252.   if (!*name || (strlen(name) < 5))
  2253.   {  return nil;
  2254.   }
  2255.   extension = name + (strlen(name) - 4);
  2256.   if (!strcmp(extension, ".eve"))
  2257.   {  return [self buildNewShapeHierarchyFromEveFile:name];
  2258.   }
  2259.   if (!strcmp(extension, ".rib"))
  2260.   {  return [self buildNewShapeHierarchyFromRIBFile:name];
  2261.   }
  2262.  
  2263.   return nil;
  2264. }
  2265.  
  2266. - takeInitialImage:sender  {  return [camera setImageFile:[sender stringValue]]; }
  2267. - takeInitialImageFile:(const char *)n  {  return [camera setImageFile:n]; }
  2268.  
  2269. - (int)trackballAffects { return [camera trackballAffects]; }
  2270. - takeTrackballAffectsFromMatrix:sender {  return [camera takeTrackballAffectsFromMatrix:sender]; }
  2271.  
  2272. - (int)trackballXYZ { return [camera trackballXYZ]; }
  2273. - takeTrackballXYZFromMatrix:sender {  return [camera takeTrackballXYZFromMatrix:sender]; }
  2274.  
  2275.  
  2276. // history stuff
  2277. - takeStatusText:sender  { statusText = sender; return [camera takeStatusText:sender]; }
  2278.  
  2279.  
  2280. // scene clock stuff
  2281. - takeSceneClockTime:sender  { [sceneClock setCurrentTime:[sender floatValue]]; return self; }
  2282. - takeSceneClockSamplesPerSecond:sender {  [sceneClock setSamplesPerSecond:[sender floatValue]]; return self; }
  2283. - takeSceneClockIncrement:sender  {  [sceneClock setIncrement:[sender floatValue]]; return self;  }
  2284. - takeSceneClockSkip:sender  {  [sceneClock setSkip:[sender floatValue]]; return self;  }
  2285. - takeSceneClockRatio:sender  {  [sceneClock setRatio:[sender floatValue]]; return self; }
  2286. - takeSceneClockMark:sender { [sceneClock takeMark:sender]; return self; }
  2287.   // scene clock informal protocol
  2288. - rewind:sender { [sceneClock rewind:sender]; return self; }
  2289. - pause:sender { [sceneClock pause:sender]; return self; }
  2290. - play:sender { [sceneClock play:sender]; return self; }
  2291. - increment:sender { [sceneClock increment:sender]; return self; }
  2292. - decrement:sender { [sceneClock decrement:sender]; return self; }
  2293. - fastForward:sender { [sceneClock fastForward:sender]; return self; }
  2294. - takeMark:sender { [sceneClock takeMark:sender]; return self; }
  2295. - findLastSampleAndSetMark:sender  {  [sceneClock setMark:[[camera worldShape] lastSampleIsAt]]; return self; }
  2296.  
  2297. ////////////////////////////////////////////////////////////////////
  2298. //            Dragging stuff
  2299. ///////////////////////////////////////////////////////////////////
  2300.  
  2301. - (NXDragOperation)draggingEntered:(id <NXDraggingInfo>)sender
  2302. {
  2303.     Pasteboard    *pboard;
  2304.     char          *argv;
  2305.     int           len;
  2306.     const NXAtom  *theType;
  2307.     char          *extension;
  2308.     NXEvent       *theEvent = [NXApp currentEvent];
  2309.     
  2310.  
  2311.     pboard = [sender draggingPasteboard];
  2312.     theType = [pboard types];
  2313.  
  2314.     if (*theType != NXFilenamePboardType)
  2315.     {  if ([pboard readType:NXFilenamePboardType data:&argv length:&len] == nil)
  2316.        {  fprintf(stderr, "unable to read filename from pasteboard.\n"); fflush(stderr);
  2317.       return NX_DragOperationNone;
  2318.        }
  2319.        else
  2320.        {  // has to be at least "x.rib" 
  2321.           extension = argv + (strlen(argv) - 4);
  2322.           if ((strlen(argv) > 5) && (!strcmp(extension, ".rib")))
  2323.           {  if (theEvent->flags & NX_ALTERNATEMASK)
  2324.              {  return NX_DragOperationCopy;
  2325.           }
  2326.           else
  2327.              {  return NX_DragOperationGeneric;
  2328.           }
  2329.           }
  2330.  
  2331.           // maybe it's a "xxxx.eve" file...
  2332.           if ((strlen(argv) > 5) && (!strcmp(extension, ".eve")))
  2333.           {  if (theEvent->flags & NX_ALTERNATEMASK)
  2334.              {  return  NX_DragOperationCopy;
  2335.              }
  2336.              else
  2337.              {  return NX_DragOperationGeneric;
  2338.              }
  2339.           }
  2340.           // maybe it's a "xxxx.mdl" file...
  2341.           if ((strlen(argv) > 5) && (!strcmp(extension, ".mdl")))
  2342.           {  if (theEvent->flags & NX_ALTERNATEMASK)
  2343.              {  return NX_DragOperationCopy;
  2344.              }
  2345.              else
  2346.              {  return  NX_DragOperationGeneric;
  2347.              }
  2348.           }
  2349.  
  2350.           // maybe it's a "xxxx.scn" file...
  2351.           if ((strlen(argv) > 5) && (!strcmp(extension, ".scn")))
  2352.           {  return NX_DragOperationGeneric;
  2353.           }
  2354.  
  2355.           // maybe it's an .slo file...
  2356.           if ((strlen(argv) > 5) && (!strcmp(extension, ".slo")))
  2357.           {  return NX_DragOperationCopy;
  2358.       }
  2359.  
  2360.           // maybe it's a .wwcam or .cam file          
  2361.           if ((strlen(argv) > 5) && (!strcmp(extension, ".cam")))
  2362.           {  return NX_DragOperationCopy;
  2363.           }
  2364.           
  2365.           // maybe it's a .cam.nib
  2366.           extension = argv + (strlen(argv) - 8);
  2367.           if ((strlen(argv) > 9) && (!strcmp(extension, ".cam.nib")))
  2368.           {  // we should set this shader as the shader for the currently selected shape
  2369.              return NX_DragOperationCopy;
  2370.           }
  2371.  
  2372.           // maybe it's a "xxxx.wwModel" file...
  2373.           extension = argv + (strlen(argv) - 8);
  2374.           if ((strlen(argv) > 9) && (!strcmp(extension, ".wwModel")))
  2375.           {  if (theEvent->flags & NX_ALTERNATEMASK)
  2376.              {  return NX_DragOperationCopy;
  2377.              }
  2378.              else
  2379.              {  return NX_DragOperationGeneric;
  2380.              }
  2381.           }
  2382.           // maybe it's a "xxxx.wwScene" file...
  2383.           extension = argv + (strlen(argv) - 8);
  2384.           if ((strlen(argv) > 9) && (!strcmp(extension, ".wwScene")))
  2385.           {  if (theEvent->flags & NX_ALTERNATEMASK)
  2386.              {  return NX_DragOperationCopy;
  2387.              }
  2388.              else
  2389.              {  return NX_DragOperationGeneric;
  2390.              }
  2391.           }
  2392.  
  2393.           // maybe it's an archived version of a WW3DShader object...
  2394.           extension = argv + (strlen(argv) - 11);
  2395.           if ((strlen(argv) > 12) && (!strcmp(extension, ".WW3DShader")))
  2396.           {  // we should set this shader as the shader for the currently selected shape
  2397.              fprintf(stderr, "should be setting current shape's shader to this unarchived one...\n");
  2398.              return NX_DragOperationNone;
  2399.           }
  2400.           
  2401.           // maybe it's a model template file...
  2402.           extension = argv + (strlen(argv) - 12);
  2403.           if ((strlen(argv) > 13) && (!strcmp(extension, ".mdlTemplate")))
  2404.           {  return NX_DragOperationCopy;
  2405.           }
  2406.           
  2407.           // maybe it's a .nib file...
  2408.           extension = argv + (strlen(argv) - 4);
  2409.           if ((strlen(argv) > 5) && (!strcmp(extension, ".nib")))
  2410.           {  // really should have some way of dropping it so the camera's interp 
  2411.              // gets it, but I guess that's what a .cam.nib is...
  2412.          return NX_DragOperationCopy;
  2413.       }
  2414.        }
  2415.     }
  2416.     return NX_DragOperationNone;
  2417. }
  2418.  
  2419.  
  2420.  
  2421. - (NXDragOperation)draggingUpdated:(id <NXDraggingInfo>)sender
  2422. {
  2423.     Pasteboard    *pboard;
  2424.     char          *argv;
  2425.     int           len;
  2426.     const NXAtom  *theType;
  2427.     char          *extension;
  2428.     NXEvent       *theEvent = [NXApp currentEvent];
  2429.     
  2430.  
  2431.     pboard = [sender draggingPasteboard];
  2432.     theType = [pboard types];
  2433.  
  2434.     if (*theType != NXFilenamePboardType)
  2435.     {  if ([pboard readType:NXFilenamePboardType data:&argv length:&len] == nil)
  2436.        {  fprintf(stderr, "unable to read filename from pasteboard.\n"); fflush(stderr);
  2437.       return NX_DragOperationNone;
  2438.        }
  2439.        else
  2440.        {  // has to be at least "x.rib" 
  2441.           extension = argv + (strlen(argv) - 4);
  2442.           if ((strlen(argv) > 5) && (!strcmp(extension, ".rib")))
  2443.           {  if (theEvent->flags & NX_ALTERNATEMASK)
  2444.              {  return NX_DragOperationCopy;
  2445.           }
  2446.           else
  2447.              {  return NX_DragOperationGeneric;
  2448.           }
  2449.           }
  2450.  
  2451.           // maybe it's a "xxxx.eve" file...
  2452.           if ((strlen(argv) > 5) && (!strcmp(extension, ".eve")))
  2453.           {  if (theEvent->flags & NX_ALTERNATEMASK)
  2454.              {  return  NX_DragOperationCopy;
  2455.              }
  2456.              else
  2457.              {  return NX_DragOperationGeneric;
  2458.              }
  2459.           }
  2460.           // maybe it's a "xxxx.mdl" file...
  2461.           if ((strlen(argv) > 5) && (!strcmp(extension, ".mdl")))
  2462.           {  if (theEvent->flags & NX_ALTERNATEMASK)
  2463.              {  return NX_DragOperationCopy;
  2464.              }
  2465.              else
  2466.              {  return  NX_DragOperationGeneric;
  2467.              }
  2468.           }
  2469.  
  2470.           // maybe it's a "xxxx.scn" file...
  2471.           if ((strlen(argv) > 5) && (!strcmp(extension, ".scn")))
  2472.           {  return NX_DragOperationGeneric;
  2473.           }
  2474.  
  2475.           // maybe it's an .slo file...
  2476.           if ((strlen(argv) > 5) && (!strcmp(extension, ".slo")))
  2477.           {  return NX_DragOperationCopy;
  2478.       }
  2479.  
  2480.           // maybe it's a .wwcam or .cam file          
  2481.           if ((strlen(argv) > 5) && (!strcmp(extension, ".cam")))
  2482.           {  return NX_DragOperationCopy;
  2483.           }
  2484.           
  2485.           // maybe it's a .cam.nib
  2486.           extension = argv + (strlen(argv) - 8);
  2487.           if ((strlen(argv) > 9) && (!strcmp(extension, ".cam.nib")))
  2488.           {  // we should set this shader as the shader for the currently selected shape
  2489.              return NX_DragOperationCopy;
  2490.           }
  2491.  
  2492.           // maybe it's a "xxxx.wwModel" file...
  2493.           extension = argv + (strlen(argv) - 8);
  2494.           if ((strlen(argv) > 9) && (!strcmp(extension, ".wwModel")))
  2495.           {  if (theEvent->flags & NX_ALTERNATEMASK)
  2496.              {  return NX_DragOperationCopy;
  2497.              }
  2498.              else
  2499.              {  return NX_DragOperationGeneric;
  2500.              }
  2501.           }
  2502.           // maybe it's a "xxxx.wwScene" file...
  2503.           extension = argv + (strlen(argv) - 8);
  2504.           if ((strlen(argv) > 9) && (!strcmp(extension, ".wwScene")))
  2505.           {  if (theEvent->flags & NX_ALTERNATEMASK)
  2506.              {  return NX_DragOperationCopy;
  2507.              }
  2508.              else
  2509.              {  return NX_DragOperationGeneric;
  2510.              }
  2511.           }
  2512.  
  2513.           // maybe it's an archived version of a WW3DShader object...
  2514.           extension = argv + (strlen(argv) - 11);
  2515.           if ((strlen(argv) > 12) && (!strcmp(extension, ".WW3DShader")))
  2516.           {  // we should set this shader as the shader for the currently selected shape
  2517.              fprintf(stderr, "should be setting current shape's shader to this unarchived one...\n");
  2518.              return NX_DragOperationNone;
  2519.           }
  2520.           
  2521.           // maybe it's a model template file...
  2522.           extension = argv + (strlen(argv) - 12);
  2523.           if ((strlen(argv) > 13) && (!strcmp(extension, ".mdlTemplate")))
  2524.           {  return NX_DragOperationCopy;
  2525.           }
  2526.           
  2527.           // maybe it's a .nib file...
  2528.           extension = argv + (strlen(argv) - 4);
  2529.           if ((strlen(argv) > 5) && (!strcmp(extension, ".nib")))
  2530.           {  // really should have some way of dropping it so the camera's interp 
  2531.              // gets it, but I guess that's what a .cam.nib is...
  2532.          return NX_DragOperationCopy;
  2533.       }
  2534.        }
  2535.     }
  2536.     return NX_DragOperationNone;
  2537. }
  2538.  
  2539.  
  2540. - (BOOL)performDragOperation:(id <NXDraggingInfo>)sender { return YES; }
  2541.  
  2542. // do the real work here, as it might be awhile...
  2543. - concludeDragOperation:(id <NXDraggingInfo>)sender
  2544. {
  2545.     Pasteboard    *pboard;
  2546.     char          *argv;
  2547.     int           len, ret;
  2548.     const NXAtom  *theType;
  2549.     char          *extension;
  2550.     id            newShader;
  2551.     static char   shaderName[256];
  2552.     static char   cmdBuf[MAXPATHLEN + 32];
  2553.     NXEvent       *theEvent = [NXApp currentEvent];
  2554.     
  2555.  
  2556.     pboard = [sender draggingPasteboard];
  2557.     theType = [pboard types];
  2558.  
  2559.     if (*theType != NXFilenamePboardType)
  2560.     {  if ([pboard readType:NXFilenamePboardType data:&argv length:&len] == nil)
  2561.        {  fprintf(stderr, "unable to read filename from pasteboard.\n"); fflush(stderr);
  2562.       return nil;
  2563.        }
  2564.        else
  2565.        {  // has to be at least "x.rib" 
  2566.           extension = argv + (strlen(argv) - 4);
  2567.           if ((strlen(argv) > 5) && (!strcmp(extension, ".rib")))
  2568.           {  if (theEvent->flags & NX_ALTERNATEMASK)
  2569.              {  if (![self addToShapeHierarchyFromRIBFile:argv])
  2570.                 {  return nil;
  2571.                 }
  2572.                 return self;
  2573.           }
  2574.           else
  2575.              {  if (![self buildNewShapeHierarchyFromRIBFile:argv])
  2576.                 {  return nil;
  2577.                 }
  2578.                 return self;
  2579.           }
  2580.           }
  2581.  
  2582.           // maybe it's a "xxxx.eve" file...
  2583.           if ((strlen(argv) > 5) && (!strcmp(extension, ".eve")))
  2584.           {  if (theEvent->flags & NX_ALTERNATEMASK)
  2585.              {  if (![self addToShapeHierarchyFromEveFile:argv])
  2586.                 {  return nil;
  2587.                 }
  2588.                 return self;
  2589.              }
  2590.              else
  2591.              {  if (![self buildNewShapeHierarchyFromEveFile:argv])
  2592.                 {  return nil;
  2593.                 }
  2594.                 return self;
  2595.              }
  2596.           }
  2597.           // maybe it's a "xxxx.mdl" file...
  2598.           if ((strlen(argv) > 5) && (!strcmp(extension, ".mdl")))
  2599.           {  if (theEvent->flags & NX_ALTERNATEMASK)
  2600.              {  if (![self addToShapeHierarchyFromMdlFile:argv])
  2601.                 {  return nil;
  2602.                 }
  2603.                 return self;
  2604.              }
  2605.              else
  2606.              {  if (![self buildNewShapeHierarchyFromMdlFile:argv])
  2607.                 {  return nil;
  2608.                 }
  2609.                 return self;
  2610.              }
  2611.           }
  2612.  
  2613.           // maybe it's a "xxxx.scn" file...
  2614.           if ((strlen(argv) > 5) && (!strcmp(extension, ".scn")))
  2615.           {  if (![self buildNewShapeHierarchyFromSceneFile:argv])
  2616.              {  return nil;
  2617.              }
  2618.              return self;
  2619.           }
  2620.  
  2621.           // maybe it's an .slo file...
  2622.           if ((strlen(argv) > 5) && (!strcmp(extension, ".slo")))
  2623.           {  // we should set this shader as the shader for the currently selected shape
  2624.              fprintf(stderr, "setting current shape's shader...\n");
  2625.          basename(argv, ".slo", shaderName);
  2626.          newShader = [(WW3DShader *)[[WW3DShader alloc] init] setShader:shaderName];
  2627.          if (!newShader)
  2628.          {  return nil;
  2629.          }
  2630.          [[camera currentShape] setShader_:newShader];
  2631.          return self;
  2632.       }
  2633.  
  2634.           // maybe it's a .wwcam or .cam file          
  2635.           if ((strlen(argv) > 5) && (!strcmp(extension, ".cam")))
  2636.           {  // we should set this shader as the shader for the currently selected shape
  2637.              sprintf(cmdBuf, "source %s", argv);
  2638.              ret = [[camera tclInterp] eval:cmdBuf];
  2639.              if (ret != TCL_OK)
  2640.              {  char *errorInfo = Tcl_GetVar([[camera tclInterp] interp], "errorInfo", 0);
  2641.                 NXLogError("problem sourcing file:\n%s", errorInfo);
  2642.                 return nil;  
  2643.              }  
  2644.              return self;
  2645.           }
  2646.           
  2647.           // maybe it's a .cam.nib
  2648.           extension = argv + (strlen(argv) - 8);
  2649.           if ((strlen(argv) > 9) && (!strcmp(extension, ".cam.nib")))
  2650.           {  // we should set this shader as the shader for the currently selected shape
  2651.              [[camera tclInterp] loadControlPanel:argv modally:NO];
  2652.              return self;
  2653.           }
  2654.  
  2655.           // maybe it's a "xxxx.wwModel" file...
  2656.           extension = argv + (strlen(argv) - 8);
  2657.           if ((strlen(argv) > 9) && (!strcmp(extension, ".wwModel")))
  2658.           {  if (theEvent->flags & NX_ALTERNATEMASK)
  2659.              {  if (![self addToShapeHierarchyFromMdlFile:argv])
  2660.                 {  return nil;
  2661.                 }
  2662.                 return self;
  2663.              }
  2664.              else
  2665.              {  if (![self buildNewShapeHierarchyFromMdlFile:argv])
  2666.                 {  return nil;
  2667.                 }
  2668.                 return self;
  2669.              }
  2670.           }
  2671.           // maybe it's a "xxxx.wwScene" file...
  2672.           extension = argv + (strlen(argv) - 8);
  2673.           if ((strlen(argv) > 9) && (!strcmp(extension, ".wwScene")))
  2674.           {  if (theEvent->flags & NX_ALTERNATEMASK)
  2675.              {  if (![self addToShapeHierarchyFromSceneFile:argv])
  2676.                 {  return nil;
  2677.                 }
  2678.                 return self;
  2679.              }
  2680.              else
  2681.              {  if (![self buildNewShapeHierarchyFromSceneFile:argv])
  2682.                 {  return nil;
  2683.                 }
  2684.                 return self;
  2685.              }
  2686.           }
  2687.  
  2688.           // maybe it's an archived version of a WW3DShader object...
  2689.           extension = argv + (strlen(argv) - 11);
  2690.           if ((strlen(argv) > 12) && (!strcmp(extension, ".WW3DShader")))
  2691.           {  // we should set this shader as the shader for the currently selected shape
  2692.              fprintf(stderr, "should be setting current shape's shader to this unarchived one...\n");
  2693.              return self;
  2694.           }
  2695.           
  2696.           // maybe it's a model template file...
  2697.           extension = argv + (strlen(argv) - 12);
  2698.           if ((strlen(argv) > 13) && (!strcmp(extension, ".mdlTemplate")))
  2699.           {  if (![self readMdlTemplateFile:argv])
  2700.              {  return nil;
  2701.              }
  2702.              return self;
  2703.           }
  2704.           
  2705.           // maybe it's a .nib file...
  2706.           extension = argv + (strlen(argv) - 4);
  2707.           if ((strlen(argv) > 5) && (!strcmp(extension, ".nib")))
  2708.           {  // really should have some way of dropping it so the camera's interp 
  2709.              // gets it, but I guess that's what a .cam.nib is...
  2710.              [[ribParser tclInterp] loadControlPanel:argv modally:NO];
  2711.          return self;
  2712.       }
  2713.        }
  2714.     }
  2715.     return nil;
  2716. }
  2717.  
  2718. - takeTreatAttributeBeginLikeStartShape:sender 
  2719. {  [ribParser takeTreatAttributeBeginLikeStartShape:sender];
  2720.    return self; 
  2721. }
  2722.  
  2723. - takeTreatTransformBeginLikeAttributeBegin:sender 
  2724. {  [ribParser takeTreatTransformBeginLikeAttributeBegin:sender];
  2725.    return self; 
  2726. }
  2727.  
  2728. - takeApplyShadersDirectlyToCurrentShape:sender 
  2729. {  [ribParser takeApplyShadersDirectlyToCurrentShape:sender];
  2730.    return self; 
  2731. }
  2732.  
  2733. - takeAmbientLightState:sender 
  2734. {  [camera takeAmbientLightState:sender];  
  2735.    [delegate sceneWasUpdated:camera]; 
  2736.    return [self revertControlPanel];
  2737. }
  2738. - takeAmbientLightIntensity:sender 
  2739. {  [camera takeAmbientLightIntensity:sender]; 
  2740.    [delegate sceneWasUpdated:camera]; 
  2741.    return [self revertControlPanel]; 
  2742. }
  2743. - takeAmbientLightColor:sender 
  2744. {  [camera takeAmbientLightColor:sender];  
  2745.    [delegate sceneWasUpdated:camera]; 
  2746.    return [self revertControlPanel];
  2747. }
  2748. - takeLeftLightState:sender 
  2749. {  [camera takeLeftLightState:sender];  
  2750.    [delegate sceneWasUpdated:camera]; 
  2751.    return [self revertControlPanel];
  2752. }
  2753. - takeLeftLightIntensity:sender 
  2754. {  [camera takeLeftLightIntensity:sender];  
  2755.    [delegate sceneWasUpdated:camera]; 
  2756.    return [self revertControlPanel];
  2757. }
  2758. - takeLeftLightColor:sender 
  2759. {  [camera takeLeftLightColor:sender];  
  2760.    [delegate sceneWasUpdated:camera]; 
  2761.    return [self revertControlPanel];
  2762. }
  2763. - takeRightLightState:sender 
  2764. {  [camera takeRightLightState:sender];  
  2765.    [delegate sceneWasUpdated:camera]; 
  2766.    return [self revertControlPanel];
  2767. }
  2768. - takeRightLightIntensity:sender 
  2769. {  [camera takeRightLightIntensity:sender];  
  2770.    [delegate sceneWasUpdated:camera]; 
  2771.    return [self revertControlPanel];
  2772. }
  2773. - takeRightLightColor:sender 
  2774. {  [camera takeRightLightColor:sender];  
  2775.    [delegate sceneWasUpdated:camera]; 
  2776.    return [self revertControlPanel];
  2777. }
  2778.  
  2779. - takeRenderWorldAsBox:sender 
  2780. {  [camera takeRenderWorldAsBox:sender];  
  2781.    [delegate sceneWasUpdated:camera]; 
  2782.    return [self revertControlPanel];
  2783. }
  2784. - takeRenderCurrentAsBox:sender 
  2785. {  [camera takeRenderCurrentAsBox:sender];  
  2786.    [delegate sceneWasUpdated:camera]; 
  2787.    return [self revertControlPanel];
  2788. }
  2789. - takeWorldIsVisible:sender 
  2790. {  [camera takeWorldIsVisible:sender];  
  2791.    [delegate sceneWasUpdated:camera]; 
  2792.    return [self revertControlPanel];
  2793. }
  2794. - takeCurrentIsVisible:sender 
  2795. {  [camera takeCurrentIsVisible:sender];  
  2796.    [delegate sceneWasUpdated:camera]; 
  2797.    return [self revertControlPanel];
  2798. }
  2799.  
  2800. - (BOOL)treatTransformBeginLikeAttributeBegin {  return [ribParser treatTransformBeginLikeAttributeBegin]; }
  2801.  
  2802. - (BOOL)renderWorldAsBox { return [camera renderWorldAsBox]; }
  2803. - (BOOL)renderCurrentAsBox { return [camera renderCurrentAsBox]; }
  2804. - (BOOL)worldIsVisible { return [camera worldIsVisible]; }
  2805. - (BOOL)currentIsVisible { return [camera currentIsVisible]; }
  2806.  
  2807. - (BOOL)ambientLightState { return [camera ambientLightState]; }
  2808. - (RtFloat)ambientLightIntensity { return [camera ambientLightIntensity]; }
  2809. - (NXColor)ambientLightColor { return [camera ambientLightColor]; }
  2810. - (BOOL)leftLightState { return [camera leftLightState]; }
  2811. - (RtFloat)leftLightIntensity { return [camera leftLightIntensity]; }
  2812. - (NXColor)leftLightColor { return [camera leftLightColor]; }
  2813. - (BOOL)rightLightState { return [camera rightLightState]; }
  2814. - (RtFloat)rightLightIntensity { return [camera rightLightIntensity]; }
  2815. - (NXColor)rightLightColor { return [camera rightLightColor]; }
  2816.  
  2817. - sendStringToCamera:sender 
  2818. {  
  2819.    int   ret;
  2820.    char  *retString;
  2821.    id    tclInterp = [camera tclInterp];
  2822.    BOOL  oldFlag = [tclInterp showErrors];
  2823.  
  2824.  
  2825.    if (cameraHistoryText)
  2826.    {  [cameraHistoryText setSel:[cameraHistoryText textLength] :[cameraHistoryText textLength]];
  2827.       [cameraHistoryText setSelGray:NX_BLACK];
  2828.       [cameraHistoryText replaceSel:"--> "];
  2829.       [cameraHistoryText setSelColor:sendTextColor];
  2830.       [cameraHistoryText replaceSel:[sender stringValue]];
  2831.       [cameraHistoryText replaceSel:"\n"];
  2832.       [cameraHistoryText scrollSelToVisible];
  2833.    }
  2834.    if ([sender respondsTo:@selector(selectedCell)])
  2835.    {  sender = [sender selectedCell];
  2836.    }
  2837.  
  2838.    // the the tcl interp we want to handle our own errors
  2839.    [tclInterp setShowErrors:NO];
  2840.    retString = [tclInterp eval:[sender stringValue] :&ret];
  2841.    [tclInterp setShowErrors:oldFlag];
  2842.    if (cameraHistoryText)
  2843.    {  if (ret)
  2844.       {  [cameraHistoryText setSelGray:NX_BLACK];
  2845.          [cameraHistoryText replaceSel:"ERROR: "];
  2846.          [cameraHistoryText replaceSel:retString];
  2847.          [cameraHistoryText replaceSel:"\n"];
  2848.          [cameraHistoryText scrollSelToVisible];
  2849.       }
  2850.       else
  2851.       {  [cameraHistoryText setSelGray:NX_BLACK];
  2852.          [cameraHistoryText replaceSel:"<-- "];
  2853.          [cameraHistoryText setSelColor:replyTextColor];
  2854.          [cameraHistoryText replaceSel:retString];
  2855.          [cameraHistoryText replaceSel:"\n"];
  2856.          [cameraHistoryText scrollSelToVisible];
  2857.       }
  2858.    }
  2859.    if (retString) { free(retString); }
  2860.    [cameraInterpTextField selectText:nil];
  2861.  
  2862.    return self;
  2863. }
  2864.  
  2865.  
  2866. - sendStringToShapes:sender 
  2867. {  
  2868.    int   ret;
  2869.    char  *retString;
  2870.    id    tclInterp = [ribParser tclInterp];
  2871.    BOOL  oldFlag = [tclInterp showErrors];
  2872.  
  2873.  
  2874.    if (shapeHistoryText)
  2875.    {  [shapeHistoryText setSel:[shapeHistoryText textLength] :[shapeHistoryText textLength]];
  2876.       [shapeHistoryText setSelGray:NX_BLACK];
  2877.       [shapeHistoryText replaceSel:"--> "];
  2878.       [shapeHistoryText setSelColor:sendTextColor];
  2879.       [shapeHistoryText replaceSel:[sender stringValue]];
  2880.       [shapeHistoryText replaceSel:"\n"];
  2881.       [shapeHistoryText scrollSelToVisible];
  2882.    }
  2883.    if ([sender respondsTo:@selector(selectedCell)])
  2884.    {  sender = [sender selectedCell];
  2885.    }
  2886.  
  2887.    // the the tcl interp we want to handle our own errors
  2888.    [tclInterp setShowErrors:NO];
  2889.    retString = [tclInterp eval:[sender stringValue] :&ret];
  2890.    [tclInterp setShowErrors:oldFlag];
  2891.    if (shapeHistoryText)
  2892.    {  if (ret)
  2893.       {  [shapeHistoryText setSelGray:NX_BLACK];
  2894.          [shapeHistoryText replaceSel:"ERROR: "];
  2895.          [shapeHistoryText replaceSel:retString];
  2896.          [shapeHistoryText replaceSel:"\n"];
  2897.          [shapeHistoryText scrollSelToVisible];
  2898.       }
  2899.       else
  2900.       {  [shapeHistoryText setSelGray:NX_BLACK];
  2901.          [shapeHistoryText replaceSel:"<-- "];
  2902.          [shapeHistoryText setSelColor:replyTextColor];
  2903.          [shapeHistoryText replaceSel:retString];
  2904.          [shapeHistoryText replaceSel:"\n"];
  2905.          [shapeHistoryText scrollSelToVisible];
  2906.       }
  2907.    }
  2908.    [shapeInterpTextField selectText:nil];
  2909.  
  2910.    return self;
  2911. }
  2912.  
  2913.  
  2914. - updateCameraInspector:sender { [self revertCameraInspector]; return self; }
  2915.  
  2916.  
  2917. // this is kind of a hack, but necessary...
  2918. - synchCameraToSceneClock
  2919. {
  2920.    [camera synchToSceneClock:sceneClock];
  2921.  
  2922.    return self;
  2923. }
  2924.  
  2925.  
  2926.  
  2927. /// new camera stuff
  2928. - takeFocalLength:sender  {  [camera takeFocalLength:sender]; return [self revertCameraInspector]; }
  2929. - takeFocalDistance:sender {  [camera takeFocalDistance:sender]; return [self revertCameraInspector]; }
  2930. - takeFStop:sender {  [camera takeFStop:sender]; return [self revertCameraInspector]; }
  2931. - takeExposureLength:sender {  [camera takeExposureLength:sender]; return [self revertCameraInspector]; }
  2932.  
  2933. - takeShotOutputTypeFromMatrix:sender {  [camera takeShotOutputTypeFromMatrix:sender]; return [self revertCameraInspector]; }
  2934.  
  2935. - takeShotLength:sender { [camera takeShotLength:sender]; return [self revertCameraInspector];}
  2936. - takeFramesPerSecond:sender; {  [camera takeFramesPerSecond:sender];  return [self revertCameraInspector]; }
  2937. - takeFrameNumber:sender {  [camera takeFrameNumber:sender];  return [self revertCameraInspector]; }
  2938.  
  2939. - takeExposureLengthFactor:sender { [camera takeExposureLengthFactor:sender]; return [self revertCameraInspector]; } 
  2940. - takeExposureLengthPercentage:sender { [camera setExposureLengthFactor:([sender floatValue] / 100.)]; return [self revertCameraInspector]; }
  2941. - takeShotStartTime:sender  {  [camera takeShotStartTime:sender]; return [self revertCameraInspector]; }
  2942. - takeExposureLengthAsStrobe:sender { [camera setExposureLengthFactor:0.0]; return [self revertCameraInspector]; }
  2943. - takeExposureLengthAsFilm:sender { [camera setExposureLengthFactor:0.5]; return [self revertCameraInspector]; }
  2944. - takeExposureLengthAsVideo:sender { [camera setExposureLengthFactor:1.0]; return [self revertCameraInspector]; }
  2945.  
  2946. // even newer camera stuff
  2947. - takeEyePoint:sender 
  2948.    RtPoint  anEyePoint, aViewPoint;
  2949.    float    aRollAngle;
  2950.  
  2951.  
  2952.    // need to make sure that the sender is a Matrix:
  2953.    if ([sender isKindOf:[Matrix class]])
  2954.    {  [camera getEyeAt:&anEyePoint toward:&aViewPoint roll:&aRollAngle];
  2955.       N3D_XComp(anEyePoint) =  [[sender cellAt:0 :0] floatValue]; 
  2956.       N3D_YComp(anEyePoint) =  [[sender cellAt:0 :1] floatValue]; 
  2957.       N3D_ZComp(anEyePoint) =  [[sender cellAt:0 :2] floatValue]; 
  2958.       [camera setEyeAt:anEyePoint toward:aViewPoint roll:aRollAngle];
  2959.       [self revertCameraInspector]; 
  2960.       [camera display];
  2961.    }
  2962.    else
  2963.    {  NXLogError("should only send a takeEyePoint: msg from a subclass of Matrix (which %s isn't)", [[sender class] name]);
  2964.    }
  2965.  
  2966.    return self;
  2967. }
  2968.  
  2969.  
  2970. - takeLookAt:sender 
  2971.    RtPoint  anEyePoint, aViewPoint;
  2972.    float    aRollAngle;
  2973.  
  2974.  
  2975.    // need to make sure that the sender is a Matrix:
  2976.    if ([sender isKindOf:[Matrix class]])
  2977.    {  [camera getEyeAt:&anEyePoint toward:&aViewPoint roll:&aRollAngle];
  2978.       N3D_XComp(aViewPoint) =  [[sender cellAt:0 :0] floatValue]; 
  2979.       N3D_YComp(aViewPoint) =  [[sender cellAt:0 :1] floatValue]; 
  2980.       N3D_ZComp(aViewPoint) =  [[sender cellAt:0 :2] floatValue]; 
  2981.       [camera setEyeAt:anEyePoint toward:aViewPoint roll:aRollAngle];
  2982.       [self revertCameraInspector]; 
  2983.       [camera display];
  2984.    }
  2985.    else
  2986.    {  NXLogError("should only send a takeLookAt: msg from a subclass of Matrix (which %s isn't)", [[sender class] name]);
  2987.    }
  2988.  
  2989.    return self;
  2990. }
  2991.  
  2992.  
  2993. - takeRollAngle:sender 
  2994.    RtPoint  anEyePoint, aViewPoint;
  2995.    float    aRollAngle;
  2996.  
  2997.  
  2998.    [camera getEyeAt:&anEyePoint toward:&aViewPoint roll:&aRollAngle];
  2999.    aRollAngle = [sender floatValue]; 
  3000.    [camera setEyeAt:anEyePoint toward:aViewPoint roll:aRollAngle];
  3001.    [self revertCameraInspector]; 
  3002.    [camera display];
  3003.  
  3004.    return self;
  3005. }
  3006.  
  3007. - setCurrentShapeTransformMatrixToIdentity:sender
  3008. {
  3009.    [[camera currentShape] setTransformMatrix:(RtFloat (*)[4])N3DIdentityMatrix];
  3010.    [self revertControlPanel]; 
  3011.    [camera display];
  3012.    return self;
  3013. }
  3014.  
  3015. - takeCurrentShapeTransformMatrix:sender 
  3016. {  
  3017.    RtMatrix aMatrix;
  3018.  
  3019.  
  3020.    if ([sender isKindOf:[Matrix class]])
  3021.    {  aMatrix[0][0] =  [[sender cellAt:0 :0] floatValue]; 
  3022.       aMatrix[0][1] =  [[sender cellAt:0 :1] floatValue]; 
  3023.       aMatrix[0][2] =  [[sender cellAt:0 :2] floatValue]; 
  3024.       aMatrix[0][3] =  [[sender cellAt:0 :3] floatValue]; 
  3025.  
  3026.       aMatrix[1][0] =  [[sender cellAt:1 :0] floatValue]; 
  3027.       aMatrix[1][1] =  [[sender cellAt:1 :1] floatValue]; 
  3028.       aMatrix[1][2] =  [[sender cellAt:1 :2] floatValue]; 
  3029.       aMatrix[1][3] =  [[sender cellAt:1 :3] floatValue]; 
  3030.  
  3031.       aMatrix[2][0] =  [[sender cellAt:2 :0] floatValue]; 
  3032.       aMatrix[2][1] =  [[sender cellAt:2 :1] floatValue]; 
  3033.       aMatrix[2][2] =  [[sender cellAt:2 :2] floatValue]; 
  3034.       aMatrix[2][3] =  [[sender cellAt:2 :3] floatValue]; 
  3035.  
  3036.       aMatrix[3][0] =  [[sender cellAt:3 :0] floatValue]; 
  3037.       aMatrix[3][1] =  [[sender cellAt:3 :1] floatValue]; 
  3038.       aMatrix[3][2] =  [[sender cellAt:3 :2] floatValue]; 
  3039.       aMatrix[3][3] =  [[sender cellAt:3 :3] floatValue]; 
  3040.       
  3041.       [[camera currentShape] setTransformMatrix:aMatrix];
  3042.       [self revertControlPanel]; 
  3043.       [camera display];
  3044.    }
  3045.    else
  3046.    {  NXLogError("should only send a takeCurrentShapeTransformMatrix: msg from a subclass of Matrix (which %s isn't)", [[sender class] name]);
  3047.    }
  3048.  
  3049.    return self;
  3050. }
  3051.  
  3052. - setCameraPreTransformMatrixToIdentity:sender
  3053. {
  3054.    [camera setPreTransformMatrix:(RtFloat (*)[4])N3DIdentityMatrix];
  3055.    [self revertCameraInspector]; 
  3056.    [camera display];
  3057.    return self;
  3058. }
  3059.  
  3060. - takeCameraPreTransformMatrix:sender
  3061. {
  3062.    RtMatrix aMatrix;
  3063.  
  3064.  
  3065.    if ([sender isKindOf:[Matrix class]])
  3066.    {  aMatrix[0][0] =  [[sender cellAt:0 :0] floatValue]; 
  3067.       aMatrix[0][1] =  [[sender cellAt:0 :1] floatValue]; 
  3068.       aMatrix[0][2] =  [[sender cellAt:0 :2] floatValue]; 
  3069.       aMatrix[0][3] =  [[sender cellAt:0 :3] floatValue]; 
  3070.  
  3071.       aMatrix[1][0] =  [[sender cellAt:1 :0] floatValue]; 
  3072.       aMatrix[1][1] =  [[sender cellAt:1 :1] floatValue]; 
  3073.       aMatrix[1][2] =  [[sender cellAt:1 :2] floatValue]; 
  3074.       aMatrix[1][3] =  [[sender cellAt:1 :3] floatValue]; 
  3075.  
  3076.       aMatrix[2][0] =  [[sender cellAt:2 :0] floatValue]; 
  3077.       aMatrix[2][1] =  [[sender cellAt:2 :1] floatValue]; 
  3078.       aMatrix[2][2] =  [[sender cellAt:2 :2] floatValue]; 
  3079.       aMatrix[2][3] =  [[sender cellAt:2 :3] floatValue]; 
  3080.  
  3081.       aMatrix[3][0] =  [[sender cellAt:3 :0] floatValue]; 
  3082.       aMatrix[3][1] =  [[sender cellAt:3 :1] floatValue]; 
  3083.       aMatrix[3][2] =  [[sender cellAt:3 :2] floatValue]; 
  3084.       aMatrix[3][3] =  [[sender cellAt:3 :3] floatValue]; 
  3085.       
  3086.       [camera setPreTransformMatrix:aMatrix];
  3087.       [self revertCameraInspector]; 
  3088.       [camera display];
  3089.    }
  3090.    else
  3091.    {  NXLogError("should only send a takeCameraPreTransformMatrix: msg from a subclass of Matrix (which %s isn't)", [[sender class] name]);
  3092.    }
  3093.  
  3094.    return self;
  3095. }
  3096.  
  3097. // delegate methods
  3098.  
  3099. // this is sent whenever the contents of the well is changed
  3100. - wellWasUpdated:camera { [self display]; return self; }
  3101.  
  3102. // this method is sent whenever the scene changes in such a way that
  3103. // if the user rerendered the scene photorealistically, they would notice
  3104. // a difference.
  3105. - sceneWasUpdated:camera { return self; }
  3106.  
  3107. // this method is sent whenever the underlying controls on the scene were
  3108. // changed such that if the user manipulated the scene, it would react 
  3109. // differently
  3110. - cameraParametersWereUpdated:camera { [self invalidateCameraInspector]; return self; }
  3111. - controlsWereUpdated:camera { [self revertControlPanel]; return self; }
  3112.  
  3113.  
  3114. //---------------------------------------------------------------------------------------------------------
  3115. //    IB Methods
  3116. //---------------------------------------------------------------------------------------------------------
  3117.  
  3118. - (const char *)getInspectorClassName { return "WW3DWellIBInspector"; }
  3119.  
  3120.  
  3121. //---------------------------------------------------------------------------------------------------------
  3122. //    archiving Methods
  3123. //---------------------------------------------------------------------------------------------------------
  3124.  
  3125. #define typeVectorVersion1 "{ffff}{ffff}@if"
  3126. #define typeValuesVersion1 &bezelRect, &wellRect, &camera, &aspectRatioType, &aspectRatio
  3127.  
  3128. #define typeVectorVersion2 "{ffff}{ffff}@ifc"
  3129. #define typeValuesVersion2 &bezelRect, &wellRect, &camera, &aspectRatioType, &aspectRatio, &reuseImageView
  3130.  
  3131. #define typeVectorVersion3 "{ffff}{ffff}@ifc@"
  3132. #define typeValuesVersion3 &bezelRect, &wellRect, &camera, &aspectRatioType, &aspectRatio, &reuseImageView, &sceneClock
  3133.  
  3134. #define typeVector "@ifc@"
  3135. #define typeValues &camera, &aspectRatioType, &aspectRatio, &reuseImageView, &sceneClock
  3136.  
  3137. - read:(NXTypedStream*)stream 
  3138. {
  3139.     int version;
  3140.     
  3141.     [super read:stream];
  3142.     
  3143.     NX_DURING
  3144.     version = NXTypedStreamClassVersion(stream, "WW3DWell");
  3145.     if (version == 0) NXReadTypes(stream,"i",&version), version=1;
  3146.     if (version == 1) {
  3147.         NXReadTypes(stream, typeVectorVersion1, typeValuesVersion1);
  3148.         imageView = NXReadObject(stream);
  3149.         reuseImageView = YES;
  3150.         sceneClock = [[WWSceneClock alloc] init];
  3151.             useRendribInstead = NO;
  3152.             beepWhenDone = YES;
  3153.     }
  3154.     if (version == 2) {
  3155.         NXReadTypes(stream, typeVectorVersion2, typeValuesVersion2);
  3156.         imageView = NXReadObject(stream);
  3157.         sceneClock = [[WWSceneClock alloc] init];
  3158.             useRendribInstead = NO;
  3159.             beepWhenDone = YES;
  3160.     }
  3161.     if (version == 3) {
  3162.         NXReadTypes(stream, typeVectorVersion3, typeValuesVersion3);
  3163.         imageView = NXReadObject(stream);
  3164.             useRendribInstead = NO;
  3165.             beepWhenDone = YES;
  3166.     }
  3167.     if (version == 4) {
  3168.         NXReadTypes(stream, typeVector, typeValues);
  3169.         NXReadRect(stream, &bezelRect);
  3170.         NXReadRect(stream, &wellRect);
  3171.         imageView = NXReadObject(stream);
  3172.             useRendribInstead = NO;
  3173.             beepWhenDone = YES;
  3174.     }
  3175.     if (version == 5) {
  3176.         NXReadTypes(stream, typeVector, typeValues);
  3177.         NXReadRect(stream, &bezelRect);
  3178.         NXReadRect(stream, &wellRect);
  3179.         imageView = NXReadObject(stream);
  3180.         NXReadTypes(stream, "cc", &useRendribInstead, &beepWhenDone);
  3181.     }
  3182.     NX_HANDLER
  3183.     NXLogError("in read: %s, exception [%d] raised.\n", [[self class] name], NXLocalHandler.code);
  3184.     return nil;
  3185.     NX_ENDHANDLER
  3186.     
  3187.     return self;
  3188. }
  3189.  
  3190. - write:(NXTypedStream*)stream 
  3191. {
  3192.     [super write:stream];
  3193.     NXWriteTypes(stream, typeVector, typeValues);
  3194.     NXWriteRect(stream, &bezelRect);
  3195.     NXWriteRect(stream, &wellRect);
  3196.     NXWriteObjectReference(stream, imageView);
  3197.     NXWriteTypes(stream, "cc", &useRendribInstead, &beepWhenDone);
  3198.     return self;
  3199. }
  3200.  
  3201.  
  3202. @end
  3203.